Compare commits

...
113 Commits
Author SHA1 Message Date
benwoo1110 92951739fb Remove ability to unload default worlds. 2021-03-18 23:32:47 +08:00
Ben Woo e843b0711d Merge pull request #2590 from Multiverse/small-wm-updates
Small WorldManager updates
2021-03-10 06:41:18 +08:00
Ben Woo eddfaf7df0 Merge pull request #2593 from Multiverse/destination-id
Add method to get registered destination identifiers.
2021-03-10 06:39:31 +08:00
nicegamer7 d1150ab5f8 Merge pull request #2591 from Multiverse/uuid-regex
Make UUID regex less restrictive.
2021-03-09 09:46:33 -05:00
benwoo1110 1965aecfba Add method to get registered destination identifiers. 2021-03-09 20:05:23 +08:00
benwoo1110 ce34ae44d8 Make UUID regex less restrictive. 2021-03-09 11:48:26 +08:00
benwoo1110 f5a2d7bc47 Add getPotentialWorlds method to WorldManager. 2021-03-09 10:40:46 +08:00
benwoo1110 24295025ef Add option to lookup mvworlds without checking for aliases. 2021-03-09 10:35:42 +08:00
Ben Woo e3f56f6498 Merge pull request #2586 from Multiverse/reflect-helper
Add ReflectHelper class to better facilitate various reflection actions.
2021-03-09 01:18:29 +08:00
Ben Woo bd0c3cff3f Merge pull request #2587 from Multiverse/player-desination
Player destination
2021-03-09 00:32:20 +08:00
Ben Woo 7c4ab035a0 Merge pull request #2588 from Multiverse/world-name-check
Implement new WorldNameChecker
2021-03-09 00:31:58 +08:00
Ben Woo 2593080f77 Merge pull request #2567 from Multiverse/player-utils
Add support to find players based on name, UUID or selectors.
2021-03-09 00:29:22 +08:00
benwoo1110 0d4595d511 Implement new WorldNameChecker for better preliminary checks of world name. 2021-03-08 18:03:35 +08:00
benwoo1110 bf820c2c27 Add getPlayerAwareDestination to DestinationFactory. 2021-03-08 17:09:03 +08:00
benwoo1110 a12718d354 Add ReflectHelper class to better facilitate various reflection actions. 2021-03-08 16:25:33 +08:00
Ben Woo 7c59dcbcb9 Merge pull request #2494 from benwoo1110/property-fix
Fix cannot remove block currency with mvm set command.
2021-03-04 15:32:34 +08:00
Ben Woo 15cacba7c9 Merge pull request #2573 from Multiverse/java-11
Fix compiling with Java 11+
2021-03-02 09:01:38 +08:00
Ben Woo adbe88daa6 Merge pull request #2565 from Multiverse/fis-respawn-anchor
Add respawn anchor support.
2021-03-02 00:36:43 +08:00
Kermina Awad 5350c012f7 fix compiling on java 15 2021-02-25 17:48:17 -05:00
benwoo1110 a91f377cf5 Fix compile on java 11. 2021-02-24 16:40:21 +08:00
Ben Woo c3ae5ac210 Merge pull request #2539 from Multiverse/disable_buscript
Add a Config Option to Disable Buscript
2021-02-24 14:12:35 +08:00
Ben Woo f4ce740c06 Merge pull request #2568 from Multiverse/fullname-face-direction
Add support for fullname face direction.
2021-02-24 14:09:56 +08:00
Kermina Awad 3ff8d34053 add config option to disable buscript 2021-02-23 14:38:54 -05:00
benwoo1110 f362f09380 Add support for fullname face direction.
So we can do `w:world:north` on top of the current ``w:world:n`.
2021-02-21 17:19:18 +08:00
benwoo1110 62b789dff5 Add support to find players based on name, UUID or selectors. 2021-02-21 16:47:13 +08:00
benwoo1110 84a9db597a Add respawn anchor support. 2021-02-19 00:57:19 +08:00
nicegamer7 89fd700e32 Merge pull request #2489 from benwoo1110/world-UID
Adds world UID and generator details to /mvinfo command
2021-01-17 12:36:27 -05:00
Ben Woo 001a6000f8 Merge pull request #2515 from Multiverse/update_bstats
Update bStats Metrics Class
2020-12-20 12:10:52 +08:00
Kermina Awad bf61069fed update bStats Metrics class 2020-12-19 22:17:04 -05:00
Ben Woo d93def8b5b Merge pull request #2503 from Multiverse/getplayerexact
Use getPlayerExact in favour of getPlayer.
2020-12-14 10:28:58 +08:00
nicegamer7 540394e266 Merge pull request #2505 from benwoo1110/logging
Update to all use static logging.
2020-12-12 09:58:19 -05:00
benwoo1110 425b1c80cc Update to all use static logging. 2020-12-12 10:49:49 +08:00
Kermina Awad 47ae6f5378 use getPlayerExact instead of getPlayer 2020-12-11 12:48:19 -05:00
benwoo1110 48601e4215 Fix cannot remove block currency with mvm set command.
Setting currency to 0 is now considered as no currency value.
2020-11-27 21:14:27 +08:00
Alexander Krantz ed80083fe8 Fix null location when teleporting to own playerbed destination. (#2487)
* Fix teleporting to a the calling player's bed

* Change name to my-bed to prevent collisions with player names

* Re-add old player bed for backwards compatibility

* Remove second bed destination name

* Give constant more sensible name
2020-11-27 12:58:11 +08:00
Ben Woo d041e0a8d1 Merge pull request #2490 from benwoo1110/fix-tags
Update issue template with new tags.
2020-11-25 11:44:16 +08:00
benwoo1110 de85be5832 Update issue template with new tags. 2020-11-25 11:41:57 +08:00
Ben Woo 81d59d8bf5 Update issue template to use paste.gg (#2450)
* Update issue template to use paste.gg

* Update to show paste.gg as link
2020-10-27 11:56:18 -04:00
Jeremy Wood 0c2d2f4e0a One more test for the webhook... 2020-10-08 02:38:34 -04:00
Jeremy Wood 3d9108fb48 Minor change to test webhooks on new base branch. 2020-10-08 02:35:30 -04:00
Jeremy Wood 25c616bc32 Bumped version to 4.2.3-SNAPSHOT for continued development. 2020-10-08 02:21:13 -04:00
Jeremy Wood 148187025a Release version 4.2.2. 2020-10-08 00:38:58 -04:00
Jeremy Wood 115b0dc078 Dump full version output in multifile pastes. 2020-10-07 23:52:43 -04:00
Jeremy Wood 78bf6ba3bf Merge pull request #2442 from Multiverse/version_command_typo
Correct a Typo in VersionCommand
2020-10-07 23:33:13 -04:00
Kermina Awad e31c391af4 correct a typo in VersionCommand 2020-10-07 23:15:21 -04:00
Jeremy Wood 6ed4be9a64 Move back to '\n' line separators in version command. 2020-10-07 23:12:50 -04:00
Jeremy Wood d626e7e4b1 Merge pull request #2429 from benwoo1110/green-warning
More noticable warning for deprecated event
2020-10-07 22:41:54 -04:00
Jeremy Wood e7dd4fee51 Merge pull request #2430 from benwoo1110/clone-cleanup
Remove uneeded variables from clone method
2020-10-07 22:41:01 -04:00
Ben Woo 146075de69 Loads unloaded world before deleting (#2431)
* Loads unload world before deleting

Fixes issue where unloaded worlds can't be deleted.

* Missing commit line smh
2020-10-07 22:38:45 -04:00
Jeremy Wood 9fce6c54f6 Merge pull request #2435 from Multiverse/webpaste
Fix Double Prefix when Logging Version Info
2020-10-07 22:37:22 -04:00
Ben Woo f189eb3b7e Fix issue template label (#2437)
* Fix issue template label

* Remove "type: " from label
2020-10-07 22:32:32 -04:00
benwoo1110 ed77cacb1a Adds generator detail to /mvinfo command 2020-10-07 21:00:40 +08:00
Kermina Awad 2d4fe301cf fix double prefix when logging version info 2020-10-06 16:26:20 -04:00
Jeremy Wood e5fe1fe565 Bump version to 4.2.2-SNAPSHOT for continued development. 2020-10-06 15:46:37 -04:00
Jeremy Wood 83010f1a28 Release version 4.2.1. 2020-10-06 15:08:13 -04:00
Jeremy Wood 864e50e38c Add TestingMode util. 2020-10-06 15:07:56 -04:00
Jeremy Wood 0a99258f3e Bump version to 4.2.1-SNAPSHOT for continued development. 2020-10-06 15:01:42 -04:00
benwoo1110 cfae997de4 Adds world UID to /mvinfo command 2020-10-07 00:39:08 +08:00
benwoo1110 b345baf20e Remove uneeded variables from clone method 2020-10-06 21:12:18 +08:00
benwoo1110 d532052c7b More noticable warning for deprecated event
Add green color to the warning
2020-10-06 20:47:41 +08:00
Jeremy Wood 1c02fb4387 Release version 4.2.0. 2020-10-06 01:45:11 -04:00
Jeremy Wood 2a99649e1e Merge pull request #2426 from Multiverse/webpaste
Make it Easier to Upload Files with the Version Event
2020-10-06 01:24:33 -04:00
Kermina Awad 994bf922af make it easier to upload files with the version event 2020-10-06 00:47:33 -04:00
Ben Wooandwben1110 36094e2bea Disallow world names with spaces (#2393)
* Disallowed world names with spaces

* Fixed wildcard imports

* Use Pattern regex check for worldname validation

Co-authored-by: wben1110 (desktop) <unconfigured@null.spigotmc.org>
2020-10-05 23:58:18 -04:00
Jeremy Wood 6243b41956 Merge pull request #2421 from benwoo1110/issue-tag
Added auto label and config.yml to issue template
2020-10-05 21:02:06 -04:00
benwoo1110 32170cc089 Added auto label and config.yml to issue template 2020-10-05 16:39:16 +08:00
Jeremy Wood c1a3d48944 Merge pull request #2420 from benwoo1110/plugin.yml-update
Updated plugin.yml commands and some missing alias
2020-10-05 01:34:31 -04:00
nicegamer7 75855826e7 Cleanup webpaste code (#2411) 2020-10-05 01:25:15 -04:00
Jeremy Wood d35363b10c Merge pull request #2103 from blubberdiblub/make-saved-anchors-locale-insensitive
Ensure anchors are saved in a machine-readable way
2020-10-05 00:36:19 -04:00
Jeremy Wood ad1b733498 Merge pull request #2379 from rti/master
load cloned world with doLoad() instead of addWorld() (fixes #2378)
2020-10-05 00:29:25 -04:00
benwoo1110 9159dfbb7d Updated plugin.yml commands and some missing alias 2020-10-05 00:28:48 +08:00
Robert Timm b8acd339b3 load cloned world with doLoad() instead of addWorld() (fixes #2378) 2020-10-02 10:01:54 +02:00
nicegamer7 51e035eb3e Update GameMode command and increase Java support. (#2279)
* update gamerule command

* fix NPE in gamerules command and remove deprecated method

* catch buscript initialization errors

* update gamerule command to be more descriptive

* undo GameruleCommand style changes

* update legacy version reporting to include all config options

* use LF line ending for files being pasted to the web

* avoid duplicate code
2020-09-22 15:02:03 -04:00
Jeremy Wood 2fd8e3edc3 Merge pull request #2406 from Jadiction/patch-1
A, not an :P
2020-09-15 15:06:16 -04:00
Jad faf20ee36e A, not an :P 2020-09-10 18:09:58 -05:00
benwoo1110andwben1110 e1494808f3 Fixed inability to clone due to unable to copy session.lock (#2392)
* Added ability to exclude files when copying folders

* Remove wildcard imports

* Added unit testing for ignoring files as well

Co-authored-by: wben1110 (desktop) <unconfigured@null.spigotmc.org>
2020-08-27 08:47:57 -04:00
benwoo1110 05cf052204 Add GitHub issue templates (#2385)
* Added issue templates

* Fixed a typo

* Added more details to template

Added dev build link

Need to enter `/server` output

Declaration that issue is reproducible with only mv plugins

* Added capitalization to issue title
2020-08-26 13:34:37 -04:00
Jeremy Wood 242f05fc77 Merge pull request #2288 from Multiverse/webpaste
Rework Webpaste Package
2020-07-28 20:50:08 -04:00
Jeremy Wood dd29fcc1dd Merge pull request #2315 from Multiverse/another_metric_fix
Don't Report Generator Settings
2020-07-28 20:41:07 -04:00
Kermina Awad d5013546d1 don't report generator settings 2020-06-29 11:40:01 -04:00
Kermina Awad 058c0837f0 bring multi-file pastes to parity with single file pastes 2020-06-14 16:04:58 -04:00
Kermina Awad e01c646562 add paste.gg paste service 2020-06-14 16:04:17 -04:00
Jeremy Wood 3afca50930 Merge pull request #2289 from Multiverse/ammed_bstats
Correct Metric Reports
2020-06-13 18:52:43 -04:00
Kermina Awad 94ca18e95c correct some metrics 2020-06-13 14:20:36 -04:00
Kermina Awad 707eae92a8 improve javadocs, also, no need to make implementations public 2020-06-13 10:36:30 -04:00
Kermina Awad b4a4519876 no need for protected access modifier 2020-06-13 10:36:25 -04:00
Kermina Awad 4f41b7aa6e rework webpaste package 2020-06-13 10:36:21 -04:00
Kermina Awad b9267a3dfc update version command description 2020-06-13 10:36:16 -04:00
Kermina Awad a53c4214f0 add extra space for readability 2020-06-13 10:36:08 -04:00
Kermina Awad 343695e23e add notice as to why pasting to GitHub is disabled 2020-06-13 10:36:04 -04:00
Kermina Awad e17e9c8ce9 rename GithubPasteService as GitHubPasteService 2020-06-13 10:36:00 -04:00
Kermina Awad 676c3a2e3d make pasting more system agnostic 2020-06-13 10:35:58 -04:00
Kermina Awad e821611744 fix pasting to hastebin 2020-06-13 10:35:55 -04:00
Kermina Awad d69c492577 cleanup GitHub and Pastebin paste services 2020-06-13 10:35:53 -04:00
Kermina Awad eb91eefc80 fix BitlyURLShortener 2020-06-13 10:35:49 -04:00
Kermina Awad f570c81366 update version command 2020-06-13 10:35:47 -04:00
Jeremy Wood b3f23278b1 Yay for tests that use method names in strings. -.- 2020-06-13 02:01:41 -04:00
Jeremy Wood 3fa2bfa7cf Merge pull request #2280 from Multiverse/bstats
Fixes #2252, implements #1918.
2020-06-13 01:20:29 -04:00
Jeremy Wood 582d6bef1a Readd world count metric as multiline chart (for future use). 2020-06-13 01:17:00 -04:00
Jeremy Wood 04c65cc59e Cleanup new metrics implementation. (#2286)
* Refactor metrics initialization into its own class.

* Simplify the creation of metrics.

* Clean up new metrics.

* Refactor out duplicate metrics code.
2020-06-13 00:51:18 -04:00
Kermina Awad 268c4982c3 update metric implementations 2020-06-12 23:50:17 -04:00
Kermina Awad 8983a0c024 add vault as softdepend 2020-06-07 19:31:51 -04:00
Kermina Awad 1cbe901e4d lead dev should be the first author listed 2020-06-06 13:38:03 -04:00
Kermina Awad 4894abd1f1 switch to bStats 2020-06-06 13:36:53 -04:00
nicegamer7 1fac13247f Fix Travis Builds for Pull Requests (#2208)
* fix travis

* I don't think we need this

* we don't use circleci anymore
2020-05-06 13:07:48 -04:00
Jeremy Wood 59cfacf007 Merge pull request #2227 from A248/patch-1
Fix NPE for invalid world argument in gamerule cmd
2020-05-05 21:19:42 -04:00
Jeremy Wood 5f916fbf27 Merge pull request #2242 from wellnesscookie/master
Fixes alias not clearing after cloning the world
2020-05-05 21:14:12 -04:00
wellnesscookie c70e254dbf Fixes alias not clearing after cloning the world
This will rather set an alias to an empty string which will automatically be resulted in alias being as same as the name of the cloned world.
Previously, it was not working as intended and kept the alias of the oldWorld.
2020-04-30 20:43:11 +02:00
A248 9d42a05759 Fix NPE for invalid world argument in gamerule cmd
Stumbled upon an NPE when using /mv gamerule. I realised it was because I had specified a nonexistent world. This will fix it.
2020-04-16 18:31:23 -04:00
Niels Boehm 46f8453b5b Ensure archors are saved in a machine-readable way
`locationToString()` is primarily used by the AnchorManager to persist
anchors to disk (the other use is for logging).

In a locale that uses periods as decimal separator, this works fine and
the anchors can be loaded when the server restarts.

However, in a locale that doesn't use periods (but commas, for instance)
this produces an `anchors.yml` that cannot be parsed when loaded.

Tying the string formatting in `locationToString()` to an English locale
makes it behave as expected, regardless of the external locale setting.
2019-09-23 14:54:35 +02:00
Jeremy Wood b4b0940918 Added additional configuration option to disable the donation messages. 2019-08-26 13:47:54 -04:00
Jeremy Wood 22ad7214b0 Made the donation messages at startup hidden with silent start. 2019-08-26 13:47:26 -04:00
Jeremy Wood 1ba693ffd5 Bumped version to 4.1.1-SNAPSHOT for continued development. 2019-08-23 15:38:51 -04:00
72 changed files with 2256 additions and 871 deletions

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: 💬 ​Multiverse Discord Server
url: https://discord.gg/NZtfKky
about: Need help with using Multiverse-Core or just want to chat with the devs? Join the Multiverse Discord Server for help!
+56
View File
@@ -0,0 +1,56 @@
---
name: ❓ Help!
about: Encountered a problem with Multiverse-Core? Not sure how to fix it?
title: ''
labels: 'Type: Assistance'
assignees: ''
---
<!-- Multiverse-Core help guide
Don't write inside the arrows as they will be hidden when you post your issue.
Get latest build from: http://ci.onarandombox.com/view/Multiverse/
If you need help other submodules of Multiverse, go to their respective git repo:
Multiverse-Portals: https://github.com/Multiverse/Multiverse-Portals/issues
Multiverse-NetherPortals: https://github.com/Multiverse/Multiverse-NetherPortals/issues
Multiverse-Inventories: https://github.com/Multiverse/Multiverse-Inventories/issues
Multiverse-SignPortals: https://github.com/Multiverse/Multiverse-SignPortals/issues
Or come join our Discord server to get help sooner: https://discord.gg/NZtfKky
If you're happy to wait (or you were sent here from Discord), read on:
1. Check the Usage and FAQ pages to see if it answers your queries:
https://github.com/Multiverse/Multiverse-Core/wiki/Basics
https://github.com/Multiverse/Multiverse-Core/wiki/FAQ
2. Fill out the template.
This will help us understand what problem you've encountered and help us
find a solution.
3. When linking files, do not attach them to the post!
Copy and paste any logs into https://gist.github.com/ or other similar service.
4. Delete this line and all above lines before posting your issue! -->
### Information
* **Server version:** <!-- Insert output of `/version` command -->
* **Full output of `/mv version -p`:** <!-- Replace this with the command output's https://paste.gg/ link -->
* **Server log:** <!-- Upload `logs/latest.log` to https://gist.github.com/ -->
### Help request
**Problem**
<!-- What problem did you encounter? -->
**What I have tried**
<!-- What have you tried so far? -->
**Screenshots**
<!-- If relevant, include any screenshots here. -->
+59
View File
@@ -0,0 +1,59 @@
---
name: 🐛 Report a Bug
about: Report a Multiverse-Core bug. Only use this if you're 100% sure it's something wrong with Multiverse-Core - otherwise, try "Help!".
title: ''
labels: 'Bug: Unconfirmed'
assignees: ''
---
<!-- Multiverse-Core bug reporting guide
Don't put anything inside this block, as it won't be included in the issue.
Get latest build from: http://ci.onarandombox.com/view/Multiverse/
If you are having issues with other submodules of Multiverse, go to their respective git repo:
Multiverse-Portals: https://github.com/Multiverse/Multiverse-Portals/issues
Multiverse-NetherPortals: https://github.com/Multiverse/Multiverse-NetherPortals/issues
Multiverse-Inventories: https://github.com/Multiverse/Multiverse-Inventories/issues
Multiverse-SignPortals: https://github.com/Multiverse/Multiverse-SignPortals/issues
If you are reporting a bug, please follow the following steps:
1. Fill out the template in full.
Run the commands in the console. Don't just put "latest" as a version,
or we will ignore it.
2. When linking files, do not attach them to the post!
Copy and paste any logs into https://gist.github.com/, then paste a
link to them in the relevant parts of the template.
**DO NOT drag files into this box!**
3. Make sure not to write between the arrows, as anything there will be
hidden.
4. Delete this line and all above lines before posting your issue! -->
### Information
* **Server version:** <!-- Insert output of `/version` command -->
* **Full output of `/mv version -p`:** <!-- Replace this with the command output's https://paste.gg/ link -->
* **Server log:** <!-- Upload `logs/latest.log` to https://gist.github.com/ -->
### Details
I was **`<able / not able>`** to reproduce my issue on a freshly setup and up-to-date server with the latest version of Multiverse plugins with no other plugins and with no kinds of other server or client mods.
**Description**
<!-- Replace this with a brief summary of the bug. -->
**Steps to reproduce**
<!-- Replace this with exactly what you did to cause the bug. -->
**Expected behavior**
<!-- Replace this with what you expected to happen. -->
**Screenshots**
<!-- Replace this with screenshots, if necessary. -->
@@ -0,0 +1,54 @@
---
name: 💡 Request a Feature
about: Suggest a feature you want to see in Multiverse-Core!
title: ''
labels: 'Type: Idea'
assignees: ''
---
<!-- Multiverse-Core feature request guide
Fill out the template. Don't write inside the arrows as they will be hidden
when you post your issue.
Get latest build from: http://ci.onarandombox.com/view/Multiverse/
If you are look for other submodules of Multiverse, go to their respective git repo:
Multiverse-Portals: https://github.com/Multiverse/Multiverse-Portals/issues
Multiverse-NetherPortals: https://github.com/Multiverse/Multiverse-NetherPortals/issues
Multiverse-Inventories: https://github.com/Multiverse/Multiverse-Inventories/issues
Multiverse-SignPortals: https://github.com/Multiverse/Multiverse-SignPortals/issues
Not sure if your feature fits in Multiverse-Core? Feel free to ask on our Discord
server: https://discord.gg/NZtfKky
If you have a feature suggestion for Multiverse-Core, read the following tips:
1. Fill out the template.
This will help us understand what you're requesting and why you want us
to add it.
2. Keep it simple.
Make sure it's easy to understand what you're requesting. A good way is
to keep it to one request per GitHub issue, as we can then easily track
feature requests.
3. Check whether it has already been asked or added.
You can search the issue tracker to see if your feature has already been
requested at https://github.com/Multiverse/Multiverse-Core/issues.
4. Ask yourself: "Does this belong in Multiverse-Core?"
There are lots of features that we reject because most servers won't
need or use them. If your feature is very specific or already exists in
another plugin, it might not be a good fit for Multiverse-Core.
5. Delete this line and all above lines before posting your issue! -->
### Feature request
**Feature description**
<!-- What feature are you suggesting? -->
**How the feature is useful**
<!-- How is the feature useful to players, server owners and/or developers? -->
+1 -2
View File
@@ -3,5 +3,4 @@ jdk:
- oraclejdk8
notifications:
email: false
before_install:
- sed -i.bak -e 's|https://nexus.codehaus.org/snapshots/|https://oss.sonatype.org/content/repositories/codehaus-snapshots/|g' ~/.m2/settings.xml
dist: trusty
+1 -1
View File
@@ -13,4 +13,4 @@ Copyright (c) 2011, The Multiverse Team All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the The Multiverse Team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-3
View File
@@ -1,3 +0,0 @@
machine:
java:
version: oraclejdk8
+63 -23
View File
@@ -3,12 +3,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.onarandombox.multiversecore</groupId>
<artifactId>Multiverse-Core</artifactId>
<version>4.1.0</version>
<version>4.2.3-SNAPSHOT</version>
<name>Multiverse-Core</name>
<description>World Management Plugin</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.number>UNKNOWN</project.build.number>
<project.bitly-access-token>bitly-access-token</project.bitly-access-token>
</properties>
<repositories>
@@ -33,10 +34,9 @@
<id>minebench-repo</id>
<url>https://repo.minebench.de/</url>
</repository>
<!-- Has a copy of metrics R8-SNAPSHOT !-->
<repository>
<id>elmakers-repo</id>
<url>http://maven.elmakers.com/repository/</url>
<id>CodeMC</id>
<url>https://repo.codemc.org/repository/maven-public</url>
</repository>
</repositories>
@@ -70,6 +70,17 @@
<project.build.number>${env.BUILD_NUMBER}</project.build.number>
</properties>
</profile>
<profile>
<id>bitly</id>
<activation>
<property>
<name>env.BITLY_ACCESS_TOKEN</name>
</property>
</activation>
<properties>
<project.bitly-access-token>${env.BITLY_ACCESS_TOKEN}</project.bitly-access-token>
</properties>
</profile>
</profiles>
<build>
@@ -91,21 +102,44 @@
<version>1.4.1</version>
<executions>
<execution>
<id>replace-bitly-access-token</id>
<phase>generate-sources</phase>
<goals>
<goal>replace</goal>
</goals>
<configuration>
<basedir>${project.build.sourceDirectory}</basedir>
<includes>
<include>com/onarandombox/MultiverseCore/utils/webpaste/BitlyURLShortener.java</include>
</includes>
<replacements>
<replacement>
<token>bitly-access-token</token>
<value>${project.bitly-access-token}</value>
</replacement>
</replacements>
</configuration>
</execution>
<execution>
<id>replace-maven-version-number</id>
<phase>prepare-package</phase>
<goals>
<goal>replace</goal>
</goals>
<configuration>
<basedir>${project.build.directory}/classes</basedir>
<includes>
<include>plugin.yml</include>
</includes>
<replacements>
<replacement>
<token>maven-version-number</token>
<value>${project.version}-b${project.build.number}</value>
</replacement>
</replacements>
</configuration>
</execution>
</executions>
<configuration>
<file>target/classes/plugin.yml</file>
<replacements>
<replacement>
<token>maven-version-number</token>
<value>${project.version}-b${project.build.number}</value>
</replacement>
</replacements>
</configuration>
</plugin>
<!-- Jar Plugin -->
<plugin>
@@ -181,7 +215,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
@@ -203,8 +237,8 @@
<shadedPattern>com.onarandombox.buscript</shadedPattern>
</relocation>
<relocation>
<pattern>org.mcstats</pattern>
<shadedPattern>com.onarandombox.mcstats</shadedPattern>
<pattern>org.bstats</pattern>
<shadedPattern>com.onarandombox.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>com.dumptruckman.minecraft.util.Logging</pattern>
@@ -230,13 +264,19 @@
<plugin>
<groupId>se.eris</groupId>
<artifactId>notnull-instrumenter-maven-plugin</artifactId>
<version>0.6.8</version>
<version>1.0.0</version>
<executions>
<execution>
<goals>
<goal>instrument</goal>
<goal>tests-instrument</goal>
</goals>
<configuration>
<notNull>
<param>org.jetbrains.annotations.NotNull</param>
<param>javax.validation.constraints.NotNull</param>
</notNull>
</configuration>
</execution>
</executions>
</plugin>
@@ -283,9 +323,9 @@
<version>2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.mcstats.bukkit</groupId>
<artifactId>metrics</artifactId>
<version>R8-SNAPSHOT</version>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>1.8</version>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
@@ -319,21 +359,21 @@
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.0</version>
<version>2.0.9</version>
<type>jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-easymock</artifactId>
<version>2.0.0</version>
<version>2.0.9</version>
<type>jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.0</version>
<version>2.0.9</version>
<type>jar</type>
<scope>test</scope>
</dependency>
@@ -214,7 +214,7 @@ public class MVWorld implements MultiverseWorld {
public Double validateChange(String property, Double newValue, Double oldValue,
MVWorld object) throws ChangeDeniedException {
if (newValue <= 0) {
plugin.log(Level.FINE, "Someone tried to set a scale <= 0, aborting!");
Logging.fine("Someone tried to set a scale <= 0, aborting!");
throw new ChangeDeniedException();
}
return super.validateChange(property, newValue, oldValue, object);
@@ -297,7 +297,7 @@ public class MVWorld implements MultiverseWorld {
public GameMode validateChange(String property, GameMode newValue, GameMode oldValue,
MVWorld object) throws ChangeDeniedException {
for (Player p : plugin.getServer().getWorld(getName()).getPlayers()) {
plugin.log(Level.FINER, String.format("Setting %s's GameMode to %s",
Logging.finer(String.format("Setting %s's GameMode to %s",
p.getName(), newValue.toString()));
plugin.getPlayerListener().handleGameModeAndFlight(p, MVWorld.this);
}
@@ -319,16 +319,16 @@ public class MVWorld implements MultiverseWorld {
// verify that the location is safe
if (!bs.playerCanSpawnHereSafely(newValue)) {
// it's not ==> find a better one!
plugin.log(Level.WARNING, String.format("Somebody tried to set the spawn location for '%s' to an unsafe value! Adjusting...", getAlias()));
plugin.log(Level.WARNING, "Old Location: " + plugin.getLocationManipulation().strCoordsRaw(oldValue));
plugin.log(Level.WARNING, "New (unsafe) Location: " + plugin.getLocationManipulation().strCoordsRaw(newValue));
Logging.warning(String.format("Somebody tried to set the spawn location for '%s' to an unsafe value! Adjusting...", getAlias()));
Logging.warning("Old Location: " + plugin.getLocationManipulation().strCoordsRaw(oldValue));
Logging.warning("New (unsafe) Location: " + plugin.getLocationManipulation().strCoordsRaw(newValue));
SafeTTeleporter teleporter = plugin.getSafeTTeleporter();
newValue = teleporter.getSafeLocation(newValue, SPAWN_LOCATION_SEARCH_TOLERANCE, SPAWN_LOCATION_SEARCH_RADIUS);
if (newValue == null) {
plugin.log(Level.WARNING, "Couldn't fix the location. I have to abort the spawn location-change :/");
Logging.warning("Couldn't fix the location. I have to abort the spawn location-change :/");
throw new ChangeDeniedException();
}
plugin.log(Level.WARNING, "New (safe) Location: " + plugin.getLocationManipulation().strCoordsRaw(newValue));
Logging.warning("New (safe) Location: " + plugin.getLocationManipulation().strCoordsRaw(newValue));
}
}
return super.validateChange(property, newValue, oldValue, object);
@@ -411,7 +411,7 @@ public class MVWorld implements MultiverseWorld {
// Add limit bypass to it's parent
this.limitbypassperm.addParent("mv.bypass.playerlimit.*", true);
} catch (IllegalArgumentException e) {
this.plugin.log(Level.FINER, "Permissions nodes were already added for " + this.name);
Logging.finer("Permissions nodes were already added for " + this.name);
}
}
@@ -422,16 +422,16 @@ public class MVWorld implements MultiverseWorld {
// Verify that location was safe
if (!bs.playerCanSpawnHereSafely(location)) {
if (!this.getAdjustSpawn()) {
this.plugin.log(Level.FINE, "Spawn location from world.dat file was unsafe!!");
this.plugin.log(Level.FINE, "NOT adjusting spawn for '" + this.getAlias() + "' because you told me not to.");
this.plugin.log(Level.FINE, "To turn on spawn adjustment for this world simply type:");
this.plugin.log(Level.FINE, "/mvm set adjustspawn true " + this.getAlias());
Logging.fine("Spawn location from world.dat file was unsafe!!");
Logging.fine("NOT adjusting spawn for '" + this.getAlias() + "' because you told me not to.");
Logging.fine("To turn on spawn adjustment for this world simply type:");
Logging.fine("/mvm set adjustspawn true " + this.getAlias());
return location;
}
// If it's not, find a better one.
SafeTTeleporter teleporter = this.plugin.getSafeTTeleporter();
this.plugin.log(Level.WARNING, "Spawn location from world.dat file was unsafe. Adjusting...");
this.plugin.log(Level.WARNING, "Original Location: " + plugin.getLocationManipulation().strCoordsRaw(location));
Logging.warning("Spawn location from world.dat file was unsafe. Adjusting...");
Logging.warning("Original Location: " + plugin.getLocationManipulation().strCoordsRaw(location));
Location newSpawn = teleporter.getSafeLocation(location,
SPAWN_LOCATION_SEARCH_TOLERANCE, SPAWN_LOCATION_SEARCH_RADIUS);
// I think we could also do this, as I think this is what Notch does.
@@ -450,7 +450,7 @@ public class MVWorld implements MultiverseWorld {
this.getName(), plugin.getLocationManipulation().locationToString(newerSpawn));
return newerSpawn;
} else {
this.plugin.log(Level.SEVERE, "Safe spawn NOT found!!!");
Logging.severe("Safe spawn NOT found!!!");
}
}
}
@@ -17,11 +17,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import buscript.Buscript;
@@ -34,7 +32,6 @@ import com.onarandombox.MultiverseCore.api.MVPlugin;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MultiverseCoreConfig;
import com.onarandombox.MultiverseCore.api.MultiverseMessaging;
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.commands.AnchorCommand;
import com.onarandombox.MultiverseCore.commands.CheckCommand;
@@ -91,11 +88,14 @@ import com.onarandombox.MultiverseCore.listeners.MVWeatherListener;
import com.onarandombox.MultiverseCore.listeners.MVWorldInitListener;
import com.onarandombox.MultiverseCore.listeners.MVWorldListener;
import com.onarandombox.MultiverseCore.utils.AnchorManager;
import com.onarandombox.MultiverseCore.utils.CompatibilityLayer;
import com.onarandombox.MultiverseCore.utils.MVEconomist;
import com.onarandombox.MultiverseCore.utils.MVMessaging;
import com.onarandombox.MultiverseCore.utils.MVPermissions;
import com.onarandombox.MultiverseCore.utils.MVPlayerSession;
import com.onarandombox.MultiverseCore.utils.MaterialConverter;
import com.onarandombox.MultiverseCore.utils.TestingMode;
import com.onarandombox.MultiverseCore.utils.metrics.MetricsConfigurator;
import com.onarandombox.MultiverseCore.utils.SimpleBlockSafety;
import com.onarandombox.MultiverseCore.utils.SimpleLocationManipulation;
import com.onarandombox.MultiverseCore.utils.SimpleSafeTTeleporter;
@@ -109,7 +109,6 @@ import org.bukkit.ChatColor;
import org.bukkit.Difficulty;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.World.Environment;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.Configuration;
@@ -122,7 +121,6 @@ import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader;
import org.mcstats.Metrics;
/**
* The implementation of the Multiverse-{@link Core}.
@@ -257,6 +255,8 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
// Setup our SafeTTeleporter
this.safeTTeleporter = new SimpleSafeTTeleporter(this);
this.unsafeCallWrapper = new UnsafeCallWrapper(this);
// Setup our CompatibilityLayer
CompatibilityLayer.init();
}
@@ -309,7 +309,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
this.worldManager.loadDefaultWorlds();
this.worldManager.loadWorlds(true);
} else {
this.log(Level.SEVERE, "Your configs were not loaded. Very little will function in Multiverse.");
Logging.severe("Your configs were not loaded. Very little will function in Multiverse.");
}
this.anchorManager.loadAnchors();
@@ -340,108 +340,32 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
// Output a little snippet to show it's enabled.
Logging.config("Version %s (API v%s) Enabled - By %s", this.getDescription().getVersion(), PROTOCOL, getAuthors());
getLogger().info("Help dumptruckman keep this project alive. Become a patron! https://www.patreon.com/dumptruckman");
getLogger().info("One time donations are also appreciated: https://www.paypal.me/dumptruckman");
if (getMVConfig().isShowingDonateMessage()) {
getLogger().config("Help dumptruckman keep this project alive. Become a patron! https://www.patreon.com/dumptruckman");
getLogger().config("One time donations are also appreciated: https://www.paypal.me/dumptruckman");
}
}
private void setupMetrics() {
if (TestingMode.isDisabled()) {
MetricsConfigurator.configureMetrics(this);
}
}
/**
* Initializes the buscript javascript library.
*/
private void initializeBuscript() {
buscript = new Buscript(this);
// Add global variable "multiverse" to javascript environment
buscript.setScriptVariable("multiverse", this);
}
buscript = null;
/**
* Plotter for Environment-Values.
*/
private static final class EnvironmentPlotter extends Metrics.Plotter {
private MultiverseCore core;
private final Environment env;
public EnvironmentPlotter(MultiverseCore core, Environment env) {
super(envToString(env));
this.core = core;
this.env = env;
}
private static String envToString(Environment env) {
return new StringBuilder().append(env.name().toUpperCase().charAt(0))
.append(env.name().toLowerCase().substring(1)).toString();
}
@Override
public int getValue() {
int count = 0;
for (MultiverseWorld w : core.getMVWorldManager().getMVWorlds())
if (w.getEnvironment() == env)
count++;
core.log(Level.FINE, String.format("Tracking %d worlds of type %s", count, env));
return count;
}
}
/**
* Plotter for Generator-Values.
*/
private static final class GeneratorPlotter extends Metrics.Plotter {
private MultiverseCore core;
private final String gen;
public GeneratorPlotter(MultiverseCore core, String gen) {
super(gen);
this.core = core;
this.gen = gen;
}
@Override
public int getValue() {
int count = 0;
for (MultiverseWorld w : core.getMVWorldManager().getMVWorlds())
if (gen.equals(w.getGenerator()))
count++;
core.log(Level.FINE, String.format("Tracking %d worlds of type %s", count, gen));
return count;
}
}
private void setupMetrics() {
try {
Metrics m = new Metrics(this);
Metrics.Graph envGraph = m.createGraph("Worlds by environment");
for (Environment env : Environment.values())
envGraph.addPlotter(new EnvironmentPlotter(this, env));
Metrics.Graph loadedWorldsGraph = m.createGraph("Worlds by environment");
loadedWorldsGraph.addPlotter(new Metrics.Plotter("Loaded worlds") {
@Override
public int getValue() {
return getMVWorldManager().getMVWorlds().size();
}
});
loadedWorldsGraph.addPlotter(new Metrics.Plotter("Total number of worlds") {
@Override
public int getValue() {
return getMVWorldManager().getMVWorlds().size()
+ getMVWorldManager().getUnloadedWorlds().size();
}
});
Set<String> gens = new HashSet<String>();
for (MultiverseWorld w : this.getMVWorldManager().getMVWorlds())
gens.add(w.getGenerator());
gens.remove(null);
gens.remove("null");
Metrics.Graph genGraph = m.createGraph("Custom Generators");
for (String gen : gens)
genGraph.addPlotter(new GeneratorPlotter(this, gen));
m.start();
log(Level.FINE, "Metrics have run!");
} catch (Exception e) {
log(Level.WARNING, "There was an issue while enabling metrics: " + e.getMessage());
if (this.getMVConfig().getEnableBuscript()) {
try {
buscript = new Buscript(this);
// Add global variable "multiverse" to javascript environment
buscript.setScriptVariable("multiverse", this);
} catch (NullPointerException e) {
Logging.warning("Buscript failed to load! The script command will be disabled!");
}
}
}
@@ -465,7 +389,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
pm.registerEvents(this.entityListener, this);
pm.registerEvents(this.weatherListener, this);
pm.registerEvents(this.portalListener, this);
log(Level.INFO, "We are aware of the warning about the deprecated event. There is no alternative that allows us to do what we need to do. The performance impact is negligible.");
Logging.info(ChatColor.GREEN + "We are aware of the warning about the deprecated event. There is no alternative that allows us to do what we need to do and performance impact is negligible. It is safe to ignore.");
pm.registerEvents(this.worldListener, this);
pm.registerEvents(new MVMapListener(this), this);
}
@@ -584,13 +508,13 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
try {
wconf.load(worldsFile);
} catch (IOException e) {
log(Level.WARNING, "Cannot load worlds.yml");
Logging.warning("Cannot load worlds.yml");
} catch (InvalidConfigurationException e) {
log(Level.WARNING, "Your worlds.yml is invalid!");
Logging.warning("Your worlds.yml is invalid!");
}
if (!wconf.isConfigurationSection("worlds")) { // empty config
this.log(Level.FINE, "No worlds to migrate!");
Logging.fine("No worlds to migrate!");
return;
}
@@ -603,7 +527,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
// fine
newValues.put(entry.getKey(), entry.getValue());
} else if (entry.getValue() instanceof ConfigurationSection) {
this.log(Level.FINE, "Migrating: " + entry.getKey());
Logging.fine("Migrating: " + entry.getKey());
// we have to migrate this
WorldProperties world = new WorldProperties(Collections.EMPTY_MAP);
ConfigurationSection section = (ConfigurationSection) entry.getValue();
@@ -769,8 +693,8 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
try {
difficulty = Difficulty.valueOf(section.getString("difficulty").toUpperCase());
} catch (IllegalArgumentException e) {
this.log(Level.WARNING, "Could not parse difficulty: " + section.getString("difficulty"));
this.log(Level.WARNING, "Setting world " + entry.getKey() + " difficulty to NORMAL");
Logging.warning("Could not parse difficulty: " + section.getString("difficulty"));
Logging.warning("Setting world " + entry.getKey() + " difficulty to NORMAL");
difficulty = Difficulty.NORMAL;
}
if (difficulty != null) {
@@ -787,7 +711,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
wasChanged = true;
} else {
// huh?
this.log(Level.WARNING, "Removing unknown entry in the config: " + entry);
Logging.warning("Removing unknown entry in the config: " + entry);
// just don't add to newValues
wasChanged = true;
}
@@ -921,8 +845,12 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
/**
* {@inheritDoc}
*
* @deprecated This is now deprecated, nobody needs it any longer.
* All logging is now done with {@link Logging}.
*/
@Override
@Deprecated
public void log(Level level, String msg) {
Logging.log(level, msg);
}
@@ -1141,7 +1069,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
this.multiverseConfig.save(new File(getDataFolder(), "config.yml"));
return true;
} catch (IOException e) {
this.log(Level.SEVERE, "Could not save Multiverse config.yml config. Please check your file permissions.");
Logging.severe("Could not save Multiverse config.yml config. Please check your file permissions.");
return false;
}
}
@@ -1,12 +1,14 @@
package com.onarandombox.MultiverseCore;
import com.dumptruckman.minecraft.util.*;
import com.onarandombox.MultiverseCore.api.*;
import com.onarandombox.MultiverseCore.event.MVDebugModeEvent;
import me.main__.util.SerializationConfig.*;
import org.bukkit.Bukkit;
import java.util.Map;
import java.util.*;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.api.MultiverseCoreConfig;
import com.onarandombox.MultiverseCore.event.MVDebugModeEvent;
import me.main__.util.SerializationConfig.NoSuchPropertyException;
import me.main__.util.SerializationConfig.Property;
import me.main__.util.SerializationConfig.SerializationConfig;
import org.bukkit.Bukkit;
/**
* Our configuration.
@@ -54,6 +56,8 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements
@Property
private volatile boolean displaypermerrors;
@Property
private volatile boolean enablebuscript;
@Property
private volatile int globaldebug;
@Property
private volatile boolean silentstart;
@@ -71,6 +75,8 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements
private volatile int portalsearchradius;
@Property
private volatile boolean autopurge;
@Property
private volatile boolean idonotwanttodonate;
public MultiverseCoreConfiguration() {
super();
@@ -95,6 +101,7 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements
teleportintercept = true;
firstspawnoverride = true;
displaypermerrors = true;
enablebuscript = true;
globaldebug = 0;
messagecooldown = 5000;
teleportcooldown = 1000;
@@ -103,6 +110,7 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements
defaultportalsearch = false;
portalsearchradius = 128;
autopurge = true;
idonotwanttodonate = false;
// END CHECKSTYLE-SUPPRESSION: MagicNumberCheck
}
@@ -208,6 +216,22 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements
return this.displaypermerrors;
}
/**
* {@inheritDoc}
*/
@Override
public boolean getEnableBuscript() {
return this.enablebuscript;
}
/**
* {@inheritDoc}
*/
@Override
public void setEnableBuscript(boolean enableBuscript) {
this.enablebuscript = enableBuscript;
}
/**
* {@inheritDoc}
*/
@@ -348,4 +372,14 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements
public void setAutoPurgeEnabled(boolean autopurge) {
this.autopurge = autopurge;
}
@Override
public boolean isShowingDonateMessage() {
return !idonotwanttodonate;
}
@Override
public void setShowDonateMessage(boolean showDonateMessage) {
this.idonotwanttodonate = !showDonateMessage;
}
}
@@ -7,11 +7,17 @@
package com.onarandombox.MultiverseCore.api;
import com.dumptruckman.minecraft.util.Logging;
import org.bukkit.Server;
import java.util.logging.Level;
/** A simple API to require plugins to have a log method. */
/**
* A simple API to require plugins to have a log method.
*
* @deprecated Replaced by {@link Logging}.
* */
@Deprecated
public interface LoggablePlugin {
/**
* Logs a message at the specified level.
@@ -174,6 +174,16 @@ public interface MVWorldManager {
*/
MultiverseWorld getMVWorld(String name);
/**
* Returns a {@link MultiverseWorld} if the world with name given exists, and null if it does not.
* This will search optionally for alias names.
*
* @param name The name or optionally the alias of the world to get.
* @param checkAliases Indicates whether to check for world alias name.
* @return A {@link MultiverseWorld} or null.
*/
MultiverseWorld getMVWorld(String name, boolean checkAliases);
/**
* Returns a {@link MultiverseWorld} if it exists, and null if it does not.
*
@@ -183,13 +193,24 @@ public interface MVWorldManager {
MultiverseWorld getMVWorld(World world);
/**
* Checks to see if the given name is a valid {@link MultiverseWorld}.
* Checks to see if the given name is a valid {@link MultiverseWorld}
* Searches based on world name AND alias.
*
* @param name The name or alias of the world to check.
* @return True if the world exists, false if not.
*/
boolean isMVWorld(String name);
/**
* Checks to see if the given name is a valid {@link MultiverseWorld}.
* Optionally searches by alias is specified.
*
* @param name The name or alias of the world to check.
* @param checkAliases Indicates whether to check for world alias name.
* @return True if the world exists, false if not.
*/
boolean isMVWorld(String name, boolean checkAliases);
/**
* Checks to see if the given world is a valid {@link MultiverseWorld}.
*
@@ -198,6 +219,38 @@ public interface MVWorldManager {
*/
boolean isMVWorld(World world);
/**
* Checks if a world name is the servers default world.
*
* Generally, default world is defined in level-name of server properties file along with
* it's 2 dimensions: [world]_nether, [world]_the_end.
*
* @param world The world to check.
* @return True if world name is a default world, else false.
*/
boolean isDefaultWorld(MultiverseWorld world);
/**
* Checks if a world name is the servers default world.
*
* Generally, default world is defined in level-name of server properties file along with
* it's 2 dimensions: [world]_nether, [world]_the_end.
*
* @param worldName The name of the world to check.
* @return True if world name is a default world, else false.
*/
boolean isDefaultWorld(String worldName);
/**
* Gets all the default world names of the server.
*
* Generally, default world is defined in level-name of server properties file along with
* it's 2 dimensions: [world]_nether, [world]_the_end.
*
* @return Collection of default world names.
*/
Collection<String> getDefaultWorldNames();
/**
* Load the Worlds &amp; Settings from the configuration file.
*
@@ -314,4 +367,11 @@ public interface MVWorldManager {
* does not exist. {@code includeLoaded} if the world exists and is loaded.
*/
boolean hasUnloadedWorld(String name, boolean includeLoaded);
/**
* Get all the possible worlds that Multiverse has detected to be importable.
*
* @return A collection of world names that are deemed importable.
*/
Collection<String> getPotentialWorlds();
}
@@ -86,6 +86,18 @@ public interface MultiverseCoreConfig extends ConfigurationSerializable {
*/
boolean getDisplayPermErrors();
/**
* Sets enableBuscript.
* @param enableBuscript The new value.
*/
void setEnableBuscript(boolean enableBuscript);
/**
* Gets enableBuscript.
* @return enableBuscript.
*/
boolean getEnableBuscript();
/**
* Sets firstSpawnOverride.
* @param firstSpawnOverride The new value.
@@ -213,4 +225,18 @@ public interface MultiverseCoreConfig extends ConfigurationSerializable {
* @param autopurge True if automatic purge should be enabled.
*/
void setAutoPurgeEnabled(boolean autopurge);
/**
* Gets whether or not the donation/patreon messages are shown.
*
* @return True if donation/patreon messages should be shown.
*/
boolean isShowingDonateMessage();
/**
* Sets whether or not the donation/patreon messages are shown.
*
* @param idonotwanttodonate True if donation/patreon messages should be shown.
*/
void setShowDonateMessage(boolean idonotwanttodonate);
}
@@ -11,6 +11,7 @@ import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVDestination;
import com.onarandombox.MultiverseCore.destination.InvalidDestination;
import com.onarandombox.MultiverseCore.utils.MVPermissions;
import com.onarandombox.MultiverseCore.utils.PlayerFinder;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -37,7 +38,7 @@ public class CheckCommand extends MultiverseCommand {
@Override
public void runCommand(CommandSender sender, List<String> args) {
Player p = this.plugin.getServer().getPlayer(args.get(0));
Player p = PlayerFinder.get(args.get(0), sender);
if (p == null) {
sender.sendMessage("Could not find player " + ChatColor.GREEN + args.get(0));
sender.sendMessage("Are they online?");
@@ -7,6 +7,7 @@
package com.onarandombox.MultiverseCore.commands;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@@ -60,7 +61,7 @@ public class DebugCommand extends MultiverseCommand {
sender.sendMessage("Multiverse Debug mode is " + ChatColor.RED + "OFF");
} else {
sender.sendMessage("Multiverse Debug mode is " + ChatColor.GREEN + debugLevel);
this.plugin.log(Level.FINE, "Multiverse Debug ENABLED");
Logging.fine("Multiverse Debug ENABLED");
}
}
}
@@ -10,6 +10,7 @@ package com.onarandombox.MultiverseCore.commands;
import com.onarandombox.MultiverseCore.MultiverseCore;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameRule;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -55,21 +56,61 @@ public class GameruleCommand extends MultiverseCommand {
return;
}
final String gameRule = args.get(0);
final GameRule gameRule = GameRule.getByName(args.get(0));
final String value = args.get(1);
final World world;
if (args.size() == 2) {
world = p.getWorld();
} else {
world = Bukkit.getWorld(args.get(2));
if (world == null) {
sender.sendMessage(ChatColor.RED + "Failure!" + ChatColor.WHITE + " World " + ChatColor.AQUA + args.get(2)
+ ChatColor.WHITE + " does not exist.");
return;
}
}
if (world.setGameRuleValue(gameRule, value)) {
sender.sendMessage(ChatColor.GREEN + "Success!" + ChatColor.WHITE + " Gamerule " + ChatColor.AQUA + gameRule
+ ChatColor.WHITE + " was set to " + ChatColor.GREEN + value);
if (gameRule == null) {
sender.sendMessage(ChatColor.RED + "Failure! " + ChatColor.AQUA + args.get(0) + ChatColor.WHITE
+ " is not a valid gamerule.");
} else {
sender.sendMessage(ChatColor.RED + "Failure!" + ChatColor.WHITE + " Gamerule " + ChatColor.AQUA + gameRule
+ ChatColor.WHITE + " cannot be set to " + ChatColor.RED + value);
if (gameRule.getType() == Boolean.class) {
boolean booleanValue;
if (value.equalsIgnoreCase("true")) {
booleanValue = true;
} else if (value.equalsIgnoreCase("false")) {
booleanValue = false;
} else {
sender.sendMessage(getErrorMessage(gameRule.getName(), value) + "it can only be set to true or false.");
return;
}
if (!world.setGameRule(gameRule, booleanValue)) {
sender.sendMessage(getErrorMessage(gameRule.getName(), value) + "something went wrong.");
return;
}
} else if (gameRule.getType() == Integer.class) {
try {
if (!world.setGameRule(gameRule, Integer.parseInt(value))) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
sender.sendMessage(getErrorMessage(gameRule.getName(), value) + "it can only be set to a positive integer.");
return;
}
} else {
sender.sendMessage(ChatColor.RED + "Failure!" + ChatColor.WHITE + " Gamerule " + ChatColor.AQUA + gameRule.getName()
+ ChatColor.WHITE + " isn't supported yet, please let us know about it.");
return;
}
sender.sendMessage(ChatColor.GREEN + "Success!" + ChatColor.WHITE + " Gamerule " + ChatColor.AQUA + gameRule.getName()
+ ChatColor.WHITE + " was set to " + ChatColor.GREEN + value + ChatColor.WHITE + ".");
}
}
private String getErrorMessage(String gameRule, String value) {
return ChatColor.RED + "Failure!" + ChatColor.WHITE + " Gamerule " + ChatColor.AQUA + gameRule
+ ChatColor.WHITE + " could not be set to " + ChatColor.RED + value + ChatColor.WHITE + ", ";
}
}
@@ -10,6 +10,7 @@ package com.onarandombox.MultiverseCore.commands;
import com.onarandombox.MultiverseCore.MultiverseCore;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameRule;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -60,6 +61,11 @@ public class GamerulesCommand extends MultiverseCommand {
world = p.getWorld();
} else {
world = Bukkit.getWorld(args.get(0));
if (world == null) {
sender.sendMessage(ChatColor.RED + "Failure!" + ChatColor.WHITE + " World " + ChatColor.AQUA + args.get(0)
+ ChatColor.WHITE + " does not exist.");
return;
}
}
final StringBuilder gameRules = new StringBuilder();
@@ -68,7 +74,7 @@ public class GamerulesCommand extends MultiverseCommand {
gameRules.append(ChatColor.WHITE).append(", ");
}
gameRules.append(ChatColor.AQUA).append(gameRule).append(ChatColor.WHITE).append(": ");
gameRules.append(ChatColor.GREEN).append(world.getGameRuleValue(gameRule));
gameRules.append(ChatColor.GREEN).append(world.getGameRuleValue(GameRule.getByName(gameRule)));
}
sender.sendMessage("=== Gamerules for " + ChatColor.AQUA + world.getName() + ChatColor.WHITE + " ===");
sender.sendMessage(gameRules.toString());
@@ -9,7 +9,7 @@ package com.onarandombox.MultiverseCore.commands;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
import com.onarandombox.MultiverseCore.utils.WorldNameChecker;
import com.pneumaticraft.commandhandler.CommandHandler;
import org.bukkit.ChatColor;
import org.bukkit.World.Environment;
@@ -18,8 +18,6 @@ import org.bukkit.command.CommandSender;
import org.bukkit.permissions.PermissionDefault;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -45,55 +43,17 @@ public class ImportCommand extends MultiverseCommand {
this.worldManager = this.plugin.getMVWorldManager();
}
/**
* A very basic check to see if a folder has a level.dat file.
* If it does, we can safely assume it's a world folder.
*
* @param worldFolder The File that may be a world.
* @return True if it looks like a world, false if not.
*/
private static boolean checkIfIsWorld(File worldFolder) {
if (worldFolder.isDirectory()) {
File[] files = worldFolder.listFiles(new FilenameFilter() {
@Override
public boolean accept(File file, String name) {
return name.toLowerCase().endsWith(".dat");
}
});
if (files != null && files.length > 0) {
return true;
}
}
return false;
}
private String getPotentialWorlds() {
File worldFolder = this.plugin.getServer().getWorldContainer();
if (worldFolder == null) {
return "";
}
File[] files = worldFolder.listFiles();
String worldList = "";
Collection<MultiverseWorld> worlds = this.worldManager.getMVWorlds();
List<String> worldStrings = new ArrayList<String>();
for (MultiverseWorld world : worlds) {
worldStrings.add(world.getName());
}
for (String world : this.worldManager.getUnloadedWorlds()) {
worldStrings.add(world);
}
private String getPotentialWorldStrings() {
final Collection<String> potentialWorlds = this.worldManager.getPotentialWorlds();
StringBuilder worldList = new StringBuilder();
ChatColor currColor = ChatColor.WHITE;
for (File file : files) {
if (file.isDirectory() && checkIfIsWorld(file) && !worldStrings.contains(file.getName())) {
worldList += currColor + file.getName() + " ";
if (currColor == ChatColor.WHITE) {
currColor = ChatColor.YELLOW;
} else {
currColor = ChatColor.WHITE;
}
}
for (String world : potentialWorlds) {
worldList.append(currColor).append(world).append(' ');
currColor = currColor == ChatColor.WHITE ? ChatColor.YELLOW : ChatColor.WHITE;
}
return worldList;
return worldList.toString();
}
private String trimWorldName(String userInput) {
@@ -106,7 +66,7 @@ public class ImportCommand extends MultiverseCommand {
String worldName = trimWorldName(args.get(0));
if (worldName.toLowerCase().equals("--list") || worldName.toLowerCase().equals("-l")) {
String worldList = this.getPotentialWorlds();
String worldList = this.getPotentialWorldStrings();
if (worldList.length() > 2) {
sender.sendMessage(ChatColor.AQUA + "====[ These look like worlds ]====");
sender.sendMessage(worldList);
@@ -149,10 +109,10 @@ public class ImportCommand extends MultiverseCommand {
if (!worldFile.exists()) {
sender.sendMessage(ChatColor.RED + "FAILED.");
String worldList = this.getPotentialWorlds();
String worldList = this.getPotentialWorldStrings();
sender.sendMessage("That world folder does not exist. These look like worlds to me:");
sender.sendMessage(worldList);
} else if (!checkIfIsWorld(worldFile)) {
} else if (!WorldNameChecker.isValidWorldFolder(worldFile)) {
sender.sendMessage(ChatColor.RED + "FAILED.");
sender.sendMessage(String.format("'%s' does not appear to be a world. It is lacking a .dat file.",
worldName));
@@ -115,6 +115,7 @@ public class InfoCommand extends MultiverseCommand {
FancyColorScheme colors = new FancyColorScheme(ChatColor.AQUA, ChatColor.AQUA, ChatColor.GOLD, ChatColor.WHITE);
message.add(new FancyHeader("General Info", colors));
message.add(new FancyMessage("World Name: ", world.getName(), colors));
message.add(new FancyMessage("World UID: ", world.getCBWorld().getUID().toString(), colors));
message.add(new FancyMessage("World Alias: ", world.getColoredWorldString(), colors));
message.add(new FancyMessage("Game Mode: ", world.getGameMode().toString(), colors));
message.add(new FancyMessage("Difficulty: ", world.getDifficulty().toString(), colors));
@@ -151,6 +152,7 @@ public class InfoCommand extends MultiverseCommand {
message = new ArrayList<FancyText>();
message.add(new FancyHeader("More World Settings", colors));
message.add(new FancyMessage("World Type: ", world.getWorldType().toString(), colors));
message.add(new FancyMessage("Generator: ", world.getGenerator(), colors));
message.add(new FancyMessage("Structures: ", world.getCBWorld().canGenerateStructures() + "", colors));
message.add(new FancyMessage("Weather: ", world.isWeatherEnabled() + "", colors));
message.add(new FancyMessage("Players will get hungry: ", world.getHunger() + "", colors));
@@ -26,7 +26,7 @@ public class ListCommand extends PaginatedCoreCommand<String> {
public ListCommand(MultiverseCore plugin) {
super(plugin);
this.setName("World Listing");
this.setCommandUsage("/mv list");
this.setCommandUsage("/mv list [page]");
this.setArgRange(0, 2);
this.addKey("mvlist");
this.addKey("mvl");
@@ -27,6 +27,7 @@ public class ReloadCommand extends MultiverseCommand {
this.setCommandUsage("/mv reload");
this.setArgRange(0, 0);
this.addKey("mvreload");
this.addKey("mvr");
this.addKey("mv reload");
this.addCommandExample("/mv reload");
this.setPermission("multiverse.core.reload", "Reloads worlds.yml and config.yml.", PermissionDefault.OP);
@@ -35,6 +35,10 @@ public class ScriptCommand extends MultiverseCommand {
@Override
public void runCommand(CommandSender sender, List<String> args) {
if (plugin.getScriptAPI() == null) {
sender.sendMessage("Buscript failed to load while the server was starting. Scripts cannot be run.");
return;
}
File file = new File(plugin.getScriptAPI().getScriptFolder(), args.get(0));
if (!file.exists()) {
sender.sendMessage("That script file does not exist in the Multiverse-Core scripts directory!");
@@ -30,6 +30,7 @@ public class SetSpawnCommand extends MultiverseCommand {
this.setCommandUsage("/mv setspawn");
this.setArgRange(0, 6);
this.addKey("mvsetspawn");
this.addKey("mvsets");
this.addKey("mvss");
this.addKey("mv set spawn");
this.addKey("mv setspawn");
@@ -9,6 +9,7 @@ package com.onarandombox.MultiverseCore.commands;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
import com.onarandombox.MultiverseCore.utils.PlayerFinder;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
@@ -50,7 +51,7 @@ public class SpawnCommand extends MultiverseCommand {
sender.sendMessage("You don't have permission to teleport another player to spawn. (multiverse.core.spawn.other)");
return;
}
Player target = this.plugin.getServer().getPlayer(args.get(0));
Player target = PlayerFinder.get(args.get(0), sender);
if (target != null) {
target.sendMessage("Teleporting to this world's spawn...");
spawnAccurately(target);
@@ -7,6 +7,7 @@
package com.onarandombox.MultiverseCore.commands;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.Teleporter;
import com.onarandombox.MultiverseCore.api.MVDestination;
@@ -17,6 +18,7 @@ import com.onarandombox.MultiverseCore.destination.WorldDestination;
import com.onarandombox.MultiverseCore.enums.TeleportResult;
import com.onarandombox.MultiverseCore.event.MVTeleportEvent;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.utils.PlayerFinder;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.World;
@@ -27,7 +29,6 @@ import org.bukkit.permissions.PermissionDefault;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
/**
* Used to teleport players.
@@ -40,7 +41,7 @@ public class TeleportCommand extends MultiverseCommand {
Permission menu = new Permission("multiverse.teleport.*", "Allows you to display the teleport menu.", PermissionDefault.OP);
this.setName("Teleport");
this.setCommandUsage("/mv tp " + ChatColor.GOLD + "[PLAYER]" + ChatColor.GREEN + " {WORLD}");
this.setCommandUsage("/mv tp " + ChatColor.GOLD + "[PLAYER]" + ChatColor.GREEN + " {DESTINATION}");
this.setArgRange(1, 2);
this.addKey("mvtp");
this.addKey("mv tp");
@@ -58,7 +59,7 @@ public class TeleportCommand extends MultiverseCommand {
String destinationName;
if (args.size() == 2) {
teleportee = this.plugin.getServer().getPlayer(args.get(0));
teleportee = PlayerFinder.get(args.get(0), sender);
if (teleportee == null) {
this.messaging.sendMessage(sender, String.format("Sorry, I couldn't find player: %s%s",
ChatColor.GOLD, args.get(0)), false);
@@ -74,27 +75,14 @@ public class TeleportCommand extends MultiverseCommand {
}
teleportee = (Player) sender;
}
// Special case for cannons:
if (destinationName.matches("(?i)cannon-[\\d]+(\\.[\\d]+)?")) {
String[] cannonSpeed = destinationName.split("-");
try {
double speed = Double.parseDouble(cannonSpeed[1]);
destinationName = "ca:" + teleportee.getWorld().getName() + ":" + teleportee.getLocation().getX()
+ "," + teleportee.getLocation().getY() + "," + teleportee.getLocation().getZ() + ":"
+ teleportee.getLocation().getPitch() + ":" + teleportee.getLocation().getYaw() + ":" + speed;
} catch (Exception e) {
destinationName = "i:invalid";
}
}
DestinationFactory df = this.plugin.getDestFactory();
MVDestination d = df.getDestination(destinationName);
MVDestination d = df.getPlayerAwareDestination(teleportee, destinationName);
MVTeleportEvent teleportEvent = new MVTeleportEvent(d, teleportee, teleporter, true);
this.plugin.getServer().getPluginManager().callEvent(teleportEvent);
if (teleportEvent.isCancelled()) {
this.plugin.log(Level.FINE, "Someone else cancelled the MVTeleport Event!!!");
Logging.fine("Someone else cancelled the MVTeleport Event!!!");
return;
}
@@ -162,9 +150,9 @@ public class TeleportCommand extends MultiverseCommand {
((CustomTeleporterDestination)d).getTeleporter() : this.playerTeleporter;
TeleportResult result = teleportObject.teleport(teleporter, teleportee, d);
if (result == TeleportResult.FAIL_UNSAFE) {
this.plugin.log(Level.FINE, "Could not teleport " + teleportee.getName()
Logging.fine("Could not teleport " + teleportee.getName()
+ " to " + plugin.getLocationManipulation().strCoordsRaw(d.getLocation(teleportee)));
this.plugin.log(Level.FINE, "Queueing Command");
Logging.fine("Queueing Command");
Class<?>[] paramTypes = { CommandSender.class, Player.class, Location.class };
List<Object> items = new ArrayList<Object>();
items.add(teleporter);
@@ -10,12 +10,13 @@ package com.onarandombox.MultiverseCore.commands;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.event.MVVersionEvent;
import com.onarandombox.MultiverseCore.utils.webpaste.BitlyURLShortener;
import com.onarandombox.MultiverseCore.utils.webpaste.PasteFailedException;
import com.onarandombox.MultiverseCore.utils.webpaste.PasteService;
import com.onarandombox.MultiverseCore.utils.webpaste.PasteServiceFactory;
import com.onarandombox.MultiverseCore.utils.webpaste.PasteServiceType;
import com.onarandombox.MultiverseCore.utils.webpaste.URLShortener;
import com.onarandombox.MultiverseCore.utils.webpaste.URLShortenerFactory;
import com.onarandombox.MultiverseCore.utils.webpaste.URLShortenerType;
import com.pneumaticraft.commandhandler.CommandHandler;
import org.apache.commons.lang.StringUtils;
import org.bukkit.ChatColor;
@@ -24,10 +25,8 @@ import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.StringUtil;
import java.io.*;
import java.util.HashMap;
import java.io.File;
import java.util.List;
import java.util.Map;
@@ -35,110 +34,92 @@ import java.util.Map;
* Dumps version info to the console.
*/
public class VersionCommand extends MultiverseCommand {
private static final URLShortener SHORTENER = new BitlyURLShortener();
private static final URLShortener SHORTENER = URLShortenerFactory.getService(URLShortenerType.BITLY);
public VersionCommand(MultiverseCore plugin) {
super(plugin);
this.setName("Multiverse Version");
this.setCommandUsage("/mv version " + ChatColor.GOLD + "-[bh] [--include-plugin-list]");
this.setCommandUsage("/mv version " + ChatColor.GOLD + "[-b|-h|-p] [--include-plugin-list]");
this.setArgRange(0, 2);
this.addKey("mv version");
this.addKey("mvver");
this.addKey("mvv");
this.addKey("mvversion");
this.setPermission("multiverse.core.version",
"Dumps version info to the console, optionally to pastie.org with -p or pastebin.com with a -b.", PermissionDefault.TRUE);
"Dumps version info to the console, optionally to pastebin.com with -b, to hastebin.com using -h, or to paste.gg with -p.", PermissionDefault.TRUE);
}
private String getLegacyString() {
StringBuilder legacyFile = new StringBuilder();
legacyFile.append("[Multiverse-Core] Multiverse-Core Version: ").append(this.plugin.getDescription().getVersion()).append('\n');
legacyFile.append("[Multiverse-Core] Bukkit Version: ").append(this.plugin.getServer().getVersion()).append('\n');
legacyFile.append("[Multiverse-Core] Loaded Worlds: ").append(this.plugin.getMVWorldManager().getMVWorlds()).append('\n');
legacyFile.append("[Multiverse-Core] Multiverse Plugins Loaded: ").append(this.plugin.getPluginCount()).append('\n');
legacyFile.append("[Multiverse-Core] Economy being used: ").append(plugin.getEconomist().getEconomyName()).append('\n');
legacyFile.append("[Multiverse-Core] Permissions Plugin: ").append(this.plugin.getMVPerms().getType()).append('\n');
legacyFile.append("[Multiverse-Core] Dumping Config Values: (version ")
.append(this.plugin.getMVConfig().getVersion()).append(")").append('\n');
legacyFile.append("[Multiverse-Core] messagecooldown: ").append(plugin.getMessaging().getCooldown()).append('\n');
legacyFile.append("[Multiverse-Core] teleportcooldown: ").append(plugin.getMVConfig().getTeleportCooldown()).append('\n');
legacyFile.append("[Multiverse-Core] worldnameprefix: ").append(plugin.getMVConfig().getPrefixChat()).append('\n');
legacyFile.append("[Multiverse-Core] worldnameprefixFormat: ").append(plugin.getMVConfig().getPrefixChatFormat()).append('\n');
legacyFile.append("[Multiverse-Core] enforceaccess: ").append(plugin.getMVConfig().getEnforceAccess()).append('\n');
legacyFile.append("[Multiverse-Core] displaypermerrors: ").append(plugin.getMVConfig().getDisplayPermErrors()).append('\n');
legacyFile.append("[Multiverse-Core] teleportintercept: ").append(plugin.getMVConfig().getTeleportIntercept()).append('\n');
legacyFile.append("[Multiverse-Core] firstspawnoverride: ").append(plugin.getMVConfig().getFirstSpawnOverride()).append('\n');
legacyFile.append("[Multiverse-Core] firstspawnworld: ").append(plugin.getMVConfig().getFirstSpawnWorld()).append('\n');
legacyFile.append("[Multiverse-Core] debug: ").append(plugin.getMVConfig().getGlobalDebug()).append('\n');
legacyFile.append("[Multiverse-Core] Special Code: FRN002").append('\n');
return legacyFile.toString();
return "[Multiverse-Core] Multiverse-Core Version: " + this.plugin.getDescription().getVersion() + '\n'
+ "[Multiverse-Core] Bukkit Version: " + this.plugin.getServer().getVersion() + '\n'
+ "[Multiverse-Core] Loaded Worlds: " + this.plugin.getMVWorldManager().getMVWorlds() + '\n'
+ "[Multiverse-Core] Multiverse Plugins Loaded: " + this.plugin.getPluginCount() + '\n'
+"[Multiverse-Core] Economy being used: " + plugin.getEconomist().getEconomyName() + '\n'
+ "[Multiverse-Core] Permissions Plugin: " + this.plugin.getMVPerms().getType() + '\n'
+ "[Multiverse-Core] Dumping Config Values: (version " + this.plugin.getMVConfig().getVersion() + ")" + '\n'
+ "[Multiverse-Core] enforceaccess: " + plugin.getMVConfig().getEnforceAccess() + '\n'
+ "[Multiverse-Core] prefixchat: " + plugin.getMVConfig().getPrefixChat() + '\n'
+ "[Multiverse-Core] prefixchatformat: " + plugin.getMVConfig().getPrefixChatFormat() + '\n'
+ "[Multiverse-Core] useasyncchat: " + plugin.getMVConfig().getUseAsyncChat() + '\n'
+ "[Multiverse-Core] teleportintercept: " + plugin.getMVConfig().getTeleportIntercept() + '\n'
+ "[Multiverse-Core] firstspawnoverride: " + plugin.getMVConfig().getFirstSpawnOverride() + '\n'
+ "[Multiverse-Core] displaypermerrors: " + plugin.getMVConfig().getDisplayPermErrors() + '\n'
+ "[Multiverse-Core] enablebuscript: " + plugin.getMVConfig().getEnableBuscript() + '\n'
+ "[Multiverse-Core] globaldebug: " + plugin.getMVConfig().getGlobalDebug() + '\n'
+ "[Multiverse-Core] silentstart: " + plugin.getMVConfig().getSilentStart() + '\n'
+ "[Multiverse-Core] messagecooldown: " + plugin.getMessaging().getCooldown() + '\n'
+ "[Multiverse-Core] version: " + plugin.getMVConfig().getVersion() + '\n'
+ "[Multiverse-Core] firstspawnworld: " + plugin.getMVConfig().getFirstSpawnWorld() + '\n'
+ "[Multiverse-Core] teleportcooldown: " + plugin.getMVConfig().getTeleportCooldown() + '\n'
+ "[Multiverse-Core] defaultportalsearch: " + plugin.getMVConfig().isUsingDefaultPortalSearch() + '\n'
+ "[Multiverse-Core] portalsearchradius: " + plugin.getMVConfig().getPortalSearchRadius() + '\n'
+ "[Multiverse-Core] autopurge: " + plugin.getMVConfig().isAutoPurgeEnabled() + '\n'
+ "[Multiverse-Core] Special Code: FRN002" + '\n';
}
private String getMarkdownString() {
StringBuilder markdownString = new StringBuilder();
markdownString.append("# Multiverse-Core\n");
markdownString.append("## Overview\n");
markdownString.append("| Name | Value |\n");
markdownString.append("| --- | --- |\n");
markdownString.append("| Multiverse-Core Version | `").append(this.plugin.getDescription().getVersion()).append("` |\n");
markdownString.append("| Bukkit Version | `").append(this.plugin.getServer().getVersion()).append("` |\n");
//markdownString.append("| Loaded Worlds | `").append(this.plugin.getMVWorldManager().getMVWorlds()).append("` |\n");
markdownString.append("| Multiverse Plugins Loaded | `").append(this.plugin.getPluginCount()).append("` |\n");
markdownString.append("| Economy being used | `").append(plugin.getEconomist().getEconomyName()).append("` |\n");
markdownString.append("| Permissions Plugin | `").append(this.plugin.getMVPerms().getType()).append("` |\n");
markdownString.append("## Parsed Config\n");
markdownString.append("These are what Multiverse thought the in-memory values of the config were.\n\n");
markdownString.append("| Config Key | Value |\n");
markdownString.append("| --- | --- |\n");
markdownString.append("| version | `").append(this.plugin.getMVConfig().getVersion()).append("` |\n");
markdownString.append("| messagecooldown | `").append(plugin.getMessaging().getCooldown()).append("` |\n");
markdownString.append("| teleportcooldown | `").append(plugin.getMVConfig().getTeleportCooldown()).append("` |\n");
markdownString.append("| worldnameprefix | `").append(plugin.getMVConfig().getPrefixChat()).append("` |\n");
markdownString.append("| worldnameprefixFormat | `").append(plugin.getMVConfig().getPrefixChatFormat()).append("` |\n");
markdownString.append("| enforceaccess | `").append(plugin.getMVConfig().getEnforceAccess()).append("` |\n");
markdownString.append("| displaypermerrors | `").append(plugin.getMVConfig().getDisplayPermErrors()).append("` |\n");
markdownString.append("| teleportintercept | `").append(plugin.getMVConfig().getTeleportIntercept()).append("` |\n");
markdownString.append("| firstspawnoverride | `").append(plugin.getMVConfig().getFirstSpawnOverride()).append("` |\n");
markdownString.append("| firstspawnworld | `").append(plugin.getMVConfig().getFirstSpawnWorld()).append("` |\n");
markdownString.append("| debug | `").append(plugin.getMVConfig().getGlobalDebug()).append("` |\n");
return markdownString.toString();
return "# Multiverse-Core" + '\n'
+ "## Overview" + '\n'
+ "| Name | Value |" + '\n'
+ "| --- | --- |" + '\n'
+ "| Multiverse-Core Version | `" + this.plugin.getDescription().getVersion() + "` |" + '\n'
+ "| Bukkit Version | `" + this.plugin.getServer().getVersion() + "` |" + '\n'
+ "| Loaded Worlds | `" + this.plugin.getMVWorldManager().getMVWorlds() + "` |" + '\n'
+ "| Multiverse Plugins Loaded | `" + this.plugin.getPluginCount() + "` |" + '\n'
+ "| Economy being used | `" + plugin.getEconomist().getEconomyName() + "` |" + '\n'
+ "| Permissions Plugin | `" + this.plugin.getMVPerms().getType() + "` |" + '\n'
+ "## Parsed Config" + '\n'
+ "These are what Multiverse thought the in-memory values of the config were." + "\n\n"
+ "| Config Key | Value |" + '\n'
+ "| --- | --- |" + '\n'
+ "| version | `" + this.plugin.getMVConfig().getVersion() + "` |" + '\n'
+ "| messagecooldown | `" + plugin.getMessaging().getCooldown() + "` |" + '\n'
+ "| teleportcooldown | `" + plugin.getMVConfig().getTeleportCooldown() + "` |" + '\n'
+ "| worldnameprefix | `" + plugin.getMVConfig().getPrefixChat() + "` |" + '\n'
+ "| worldnameprefixFormat | `" + plugin.getMVConfig().getPrefixChatFormat() + "` |" + '\n'
+ "| enforceaccess | `" + plugin.getMVConfig().getEnforceAccess() + "` |" + '\n'
+ "| displaypermerrors | `" + plugin.getMVConfig().getDisplayPermErrors() + "` |" + '\n'
+ "| teleportintercept | `" + plugin.getMVConfig().getTeleportIntercept() + "` |" + '\n'
+ "| firstspawnoverride | `" + plugin.getMVConfig().getFirstSpawnOverride() + "` |" + '\n'
+ "| firstspawnworld | `" + plugin.getMVConfig().getFirstSpawnWorld() + "` |" + '\n'
+ "| debug | `" + plugin.getMVConfig().getGlobalDebug() + "` |" + '\n';
}
private String readFile(final String filename) {
String result;
try {
FileReader reader = new FileReader(filename);
BufferedReader bufferedReader = new BufferedReader(reader);
String line;
result = "";
while ((line = bufferedReader.readLine()) != null) {
result += line + '\n';
}
} catch (FileNotFoundException e) {
Logging.severe("Unable to find %s. Here's the traceback: %s", filename, e.getMessage());
e.printStackTrace();
result = String.format("ERROR: Could not load: %s", filename);
} catch (IOException e) {
Logging.severe("Something bad happend when reading %s. Here's the traceback: %s", filename, e.getMessage());
e.printStackTrace();
result = String.format("ERROR: Could not load: %s", filename);
}
return result;
}
private void addVersionInfoToEvent(MVVersionEvent event) {
// add the legacy version info
event.appendVersionInfo(this.getLegacyString());
private Map<String, String> getVersionFiles() {
Map<String, String> files = new HashMap<String, String>();
// add the legacy file, but as markdown so it's readable
// TODO Readd this in 5.0.0
// event.putDetailedVersionInfo("version.md", this.getMarkdownString());
// Add the legacy file, but as markdown so it's readable
files.put("version.md", this.getMarkdownString());
// Add the config.yml
// add config.yml
File configFile = new File(this.plugin.getDataFolder(), "config.yml");
files.put(configFile.getName(), this.readFile(configFile.getAbsolutePath()));
event.putDetailedVersionInfo("multiverse-core/config.yml", configFile);
// Add the config.yml
File worldConfig = new File(this.plugin.getDataFolder(), "worlds.yml");
files.put(worldConfig.getName(), this.readFile(worldConfig.getAbsolutePath()));
return files;
// add worlds.yml
File worldsFile = new File(this.plugin.getDataFolder(), "worlds.yml");
event.putDetailedVersionInfo("multiverse-core/worlds.yml", worldsFile);
}
@Override
@@ -148,23 +129,26 @@ public class VersionCommand extends MultiverseCommand {
sender.sendMessage("Version info dumped to console. Please check your server logs.");
}
MVVersionEvent versionEvent = new MVVersionEvent(this.getLegacyString(), this.getVersionFiles());
final Map<String, String> files = this.getVersionFiles();
MVVersionEvent versionEvent = new MVVersionEvent();
this.addVersionInfoToEvent(versionEvent);
this.plugin.getServer().getPluginManager().callEvent(versionEvent);
String versionInfo = versionEvent.getVersionInfo();
if (CommandHandler.hasFlag("--include-plugin-list", args)) {
versionInfo = versionInfo + "\nPlugins: " + getPluginList();
versionEvent.appendVersionInfo('\n' + "Plugins: " + getPluginList());
versionEvent.putDetailedVersionInfo("plugins.txt", "Plugins: " + getPluginList());
}
final String data = versionInfo;
final String versionInfo = versionEvent.getVersionInfo();
versionEvent.putDetailedVersionInfo("version.txt", versionInfo);
final Map<String, String> files = versionEvent.getDetailedVersionInfo();
// log to console
String[] lines = data.split("\n");
String[] lines = versionInfo.split("\\r?\\n");
for (String line : lines) {
if (!line.isEmpty()) {
Logging.info(line);
this.plugin.getServer().getLogger().info(line);
}
}
@@ -175,10 +159,16 @@ public class VersionCommand extends MultiverseCommand {
String pasteUrl;
if (CommandHandler.hasFlag("-b", args)) {
// private post to pastebin
pasteUrl = postToService(PasteServiceType.PASTEBIN, true, data, files);
pasteUrl = postToService(PasteServiceType.PASTEBIN, true, versionInfo, files);
} else if (CommandHandler.hasFlag("-g", args)) {
// private post to github
pasteUrl = postToService(PasteServiceType.GITHUB, true, versionInfo, files);
} else if (CommandHandler.hasFlag("-h", args)) {
// private post to pastebin
pasteUrl = postToService(PasteServiceType.HASTEBIN, true, data, files);
// private post to hastebin
pasteUrl = postToService(PasteServiceType.HASTEBIN, true, versionInfo, files);
} else if (CommandHandler.hasFlag("-p", args)) {
// private post to paste.gg
pasteUrl = postToService(PasteServiceType.PASTEGG, true, versionInfo, files);
} else {
return;
}
@@ -204,20 +194,25 @@ public class VersionCommand extends MultiverseCommand {
* @param pasteFiles Map of filenames/contents of debug info.
* @return URL of visible paste
*/
private static String postToService(PasteServiceType type, boolean isPrivate, String pasteData,
Map<String, String> pasteFiles) {
private static String postToService(PasteServiceType type, boolean isPrivate, String pasteData, Map<String, String> pasteFiles) {
PasteService ps = PasteServiceFactory.getService(type, isPrivate);
try {
String result;
if (ps.supportsMultiFile()) {
result = ps.postData(ps.encodeData(pasteFiles), ps.getPostURL());
result = ps.postData(pasteFiles);
} else {
result = ps.postData(ps.encodeData(pasteData), ps.getPostURL());
result = ps.postData(pasteData);
}
return SHORTENER.shorten(result);
if (SHORTENER != null) return SHORTENER.shorten(result);
return result;
} catch (PasteFailedException e) {
System.out.print(e);
return "Error posting to service";
e.printStackTrace();
return "Error posting to service.";
} catch (NullPointerException e) {
e.printStackTrace();
return "That service isn't supported yet.";
}
}
@@ -22,6 +22,8 @@ public class EntryFee extends SerializationConfig {
@Nullable
private Material currency;
private final Material DISABLED_MATERIAL = Material.AIR;
public EntryFee() {
super();
}
@@ -51,6 +53,9 @@ public class EntryFee extends SerializationConfig {
*/
@Nullable
public Material getCurrency() {
if (currency == null || currency.equals(DISABLED_MATERIAL)) {
return null;
}
return currency;
}
@@ -23,7 +23,7 @@ import org.bukkit.util.Vector;
* A bed-{@link MVDestination}.
*/
public class BedDestination implements MVDestination {
public static final String OLD_BED_STRING = "b:playerbed";
public static final String OWN_BED_STRING = "playerbed";
private String playername = "";
private boolean isValid;
private Location knownBedLoc;
@@ -46,11 +46,11 @@ public class BedDestination implements MVDestination {
boolean validFormat = split.length >= 1 && split.length <= 2 && split[0].equals(this.getIdentifier());
OfflinePlayer p = Bukkit.getOfflinePlayer(split[1]);
boolean validPlayer = (p != null);
boolean validPlayer = p.getName() != null && !p.getName().equals(OWN_BED_STRING);
if (validFormat && validPlayer) this.playername = p.getName();
this.isValid = destination.equals(OLD_BED_STRING) || (validFormat && validPlayer);
this.isValid = destination.equals("b:" + OWN_BED_STRING) || (validFormat && validPlayer);
return this.isValid;
}
@@ -136,6 +136,6 @@ public class BedDestination implements MVDestination {
@Override
public String toString() {
return playername.isEmpty() ? OLD_BED_STRING : ("b:" + playername);
return "b:" + (playername.isEmpty() ? OWN_BED_STRING : playername);
}
}
@@ -11,16 +11,27 @@ import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVDestination;
import com.onarandombox.MultiverseCore.commands.TeleportCommand;
import com.onarandombox.MultiverseCore.utils.PermissionTools;
import com.onarandombox.MultiverseCore.utils.PlayerFinder;
import com.pneumaticraft.commandhandler.Command;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/** A factory class that will create destinations from specific strings. */
public class DestinationFactory {
private static final Pattern CANNON_PATTERN = Pattern.compile("(?i)cannon-[\\d]+(\\.[\\d]+)?");
private MultiverseCore plugin;
private Map<String, Class<? extends MVDestination>> destList;
private Command teleportCommand;
@@ -36,6 +47,59 @@ public class DestinationFactory {
}
}
/**
* Parse a destination that has relation to sender, such as a cannon or player destination.
*
* @param teleportee The player that is going to be teleported.
* @param destinationName The destination to parse.
* @return A non-null MVDestination
*/
@NotNull
public MVDestination getPlayerAwareDestination(@NotNull Player teleportee,
@NotNull String destinationName) {
// Prioritise world, in the event that a world is named after a player online.
if (Bukkit.getWorld(destinationName) != null) {
return getDestination(destinationName);
}
Player targetPlayer = PlayerFinder.get(destinationName, teleportee);
if (targetPlayer != null) {
return getDestination("pl:" + targetPlayer.getName());
}
if (CANNON_PATTERN.matcher(destinationName).matches()) {
return getDestination(parseCannonDest(teleportee, destinationName));
}
return getDestination(destinationName);
}
/**
* Parses a cannon destination.
*
* @param teleportee The player that is going to be teleported.
* @param destinationName The destination to parse.
* @return A destination string.
*/
@NotNull
private String parseCannonDest(@NotNull Player teleportee,
@NotNull String destinationName) {
String[] cannonSpeed = destinationName.split("-");
try {
double speed = Double.parseDouble(cannonSpeed[1]);
destinationName = "ca:" + teleportee.getWorld().getName() + ":" + teleportee.getLocation().getX()
+ "," + teleportee.getLocation().getY() + "," + teleportee.getLocation().getZ() + ":"
+ teleportee.getLocation().getPitch() + ":" + teleportee.getLocation().getYaw() + ":" + speed;
}
catch (Exception e) {
destinationName = "i:invalid";
}
return destinationName;
}
/**
* Gets a new destination from a string.
* Returns a new InvalidDestination if the string could not be parsed.
@@ -101,4 +165,8 @@ public class DestinationFactory {
this.teleportCommand.addAdditonalPermission(other);
return true;
}
public Collection<String> getRegisteredIdentifiers() {
return this.destList.keySet();
}
}
@@ -50,7 +50,7 @@ public class PlayerDestination implements MVDestination {
*/
@Override
public Location getLocation(Entity e) {
Player p = plugin.getServer().getPlayer(this.player);
Player p = plugin.getServer().getPlayerExact(this.player);
Player plLoc = null;
if (e instanceof Player) {
plLoc = (Player) e;
@@ -0,0 +1,7 @@
package com.onarandombox.MultiverseCore.enums;
public enum RespawnType {
BED,
ANCHOR,
OTHER
}
@@ -1,8 +1,16 @@
package com.onarandombox.MultiverseCore.event;
import com.dumptruckman.minecraft.util.Logging;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
@@ -13,9 +21,9 @@ public class MVVersionEvent extends Event {
private final StringBuilder versionInfoBuilder;
private final Map<String, String> detailedVersionInfo;
public MVVersionEvent(String legacyVersionInfo, Map<String, String> files) {
this.versionInfoBuilder = new StringBuilder(legacyVersionInfo);
this.detailedVersionInfo = files;
public MVVersionEvent() {
versionInfoBuilder = new StringBuilder();
detailedVersionInfo = new HashMap<>();
}
private static final HandlerList HANDLERS = new HandlerList();
@@ -49,14 +57,14 @@ public class MVVersionEvent extends Event {
*
* This information is used for advanced paste services that would prefer
* to get the information as several files. Examples include config.yml or
* portals.yml.
* portals.yml. Note that the map returned is immutable.
*
* The keys are filenames, the values are the contents of the files.
*
* @return The key value mapping of files and the contents of those files.
* @return The immutable key value mapping of files and the contents of those files.
*/
public Map<String, String> getDetailedVersionInfo() {
return this.detailedVersionInfo;
return Collections.unmodifiableMap(this.detailedVersionInfo);
}
/**
@@ -66,4 +74,46 @@ public class MVVersionEvent extends Event {
public void appendVersionInfo(String moreVersionInfo) {
this.versionInfoBuilder.append(moreVersionInfo);
}
private String readFile(final String filename) {
StringBuilder result;
try {
FileReader reader = new FileReader(filename);
BufferedReader bufferedReader = new BufferedReader(reader);
String line;
result = new StringBuilder();
while ((line = bufferedReader.readLine()) != null) {
result.append(line).append("\n");
}
} catch (FileNotFoundException e) {
Logging.severe("Unable to find %s. Here's the traceback: %s", filename, e.getMessage());
e.printStackTrace();
result = new StringBuilder(String.format("ERROR: Could not load: %s", filename));
} catch (IOException e) {
Logging.severe("Something bad happend when reading %s. Here's the traceback: %s", filename, e.getMessage());
e.printStackTrace();
result = new StringBuilder(String.format("ERROR: Could not load: %s", filename));
}
return result.toString();
}
/**
* Adds a file to to the detailed version-info currently saved in this event.
* @param fileName The name of the file.
* @param contents The contents of the file.
*/
public void putDetailedVersionInfo(String fileName, String contents) {
this.detailedVersionInfo.put(fileName, contents);
}
/**
* Adds a file to to the detailed version-info currently saved in this event.
* @param filename The name of the file.
* @param file The file.
*/
public void putDetailedVersionInfo(String filename, File file) {
this.putDetailedVersionInfo(filename, readFile(file.getAbsolutePath()));
}
}
@@ -9,6 +9,7 @@ package com.onarandombox.MultiverseCore.listeners;
import java.util.logging.Level;
import com.dumptruckman.minecraft.util.Logging;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.AsyncPlayerChatEvent;
@@ -20,7 +21,7 @@ import com.onarandombox.MultiverseCore.MultiverseCore;
public class MVAsyncPlayerChatListener extends MVChatListener {
public MVAsyncPlayerChatListener(MultiverseCore plugin, MVPlayerListener playerListener) {
super(plugin, playerListener);
plugin.log(Level.FINE, "Created AsyncPlayerChatEvent listener.");
Logging.fine("Created AsyncPlayerChatEvent listener.");
}
/**
@@ -7,6 +7,7 @@
package com.onarandombox.MultiverseCore.listeners;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
@@ -98,7 +99,7 @@ public class MVEntityListener implements Listener {
* Handle people with non-standard animals: ie a patched craftbukkit.
*/
if (type == null || type.getName() == null) {
this.plugin.log(Level.FINER, "Found a null typed creature.");
Logging.finer("Found a null typed creature.");
return;
}
@@ -9,6 +9,7 @@ package com.onarandombox.MultiverseCore.listeners;
import java.util.logging.Level;
import com.dumptruckman.minecraft.util.Logging;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerChatEvent;
@@ -21,7 +22,7 @@ import com.onarandombox.MultiverseCore.MultiverseCore;
public class MVPlayerChatListener extends MVChatListener {
public MVPlayerChatListener(MultiverseCore plugin, MVPlayerListener playerListener) {
super(plugin, playerListener);
plugin.log(Level.FINE, "Registered PlayerChatEvent listener.");
Logging.fine("Registered PlayerChatEvent listener.");
}
/**
@@ -15,7 +15,9 @@ import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
import com.onarandombox.MultiverseCore.enums.RespawnType;
import com.onarandombox.MultiverseCore.event.MVRespawnEvent;
import com.onarandombox.MultiverseCore.utils.CompatibilityLayer;
import com.onarandombox.MultiverseCore.utils.PermissionTools;
import org.bukkit.GameMode;
import org.bukkit.Location;
@@ -69,9 +71,16 @@ public class MVPlayerListener implements Listener {
return;
}
RespawnType respawnType = RespawnType.OTHER;
if (event.isBedSpawn()) {
respawnType = RespawnType.BED;
}
if (CompatibilityLayer.isAnchorSpawn(event)) {
respawnType = RespawnType.ANCHOR;
}
if (mvWorld.getBedRespawn() && event.isBedSpawn()) {
this.plugin.log(Level.FINE, "Spawning " + event.getPlayer().getName() + " at their bed");
if (mvWorld.getBedRespawn() && (respawnType == RespawnType.BED || respawnType == RespawnType.ANCHOR)) {
Logging.fine("Spawning %s at their %s", event.getPlayer().getName(), respawnType);
return;
}
@@ -110,15 +119,15 @@ public class MVPlayerListener implements Listener {
public void playerJoin(PlayerJoinEvent event) {
Player p = event.getPlayer();
if (!p.hasPlayedBefore()) {
this.plugin.log(Level.FINER, "Player joined for the FIRST time!");
Logging.finer("Player joined for the FIRST time!");
if (plugin.getMVConfig().getFirstSpawnOverride()) {
this.plugin.log(Level.FINE, "Moving NEW player to(firstspawnoverride): "
Logging.fine("Moving NEW player to(firstspawnoverride): "
+ worldManager.getFirstSpawnWorld().getSpawnLocation());
this.sendPlayerToDefaultWorld(p);
}
return;
} else {
this.plugin.log(Level.FINER, "Player joined AGAIN!");
Logging.finer("Player joined AGAIN!");
if (this.plugin.getMVConfig().getEnforceAccess() // check this only if we're enforcing access!
&& !this.plugin.getMVPerms().hasPermission(p, "multiverse.access." + p.getWorld().getName(), false)) {
p.sendMessage("[MV] - Sorry you can't be in this world anymore!");
@@ -156,7 +165,7 @@ public class MVPlayerListener implements Listener {
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void playerTeleport(PlayerTeleportEvent event) {
this.plugin.log(Level.FINER, "Got teleport event for player '"
Logging.finer("Got teleport event for player '"
+ event.getPlayer().getName() + "' with cause '" + event.getCause() + "'");
if (event.isCancelled()) {
return;
@@ -166,25 +175,25 @@ public class MVPlayerListener implements Listener {
String teleporterName = MultiverseCore.getPlayerTeleporter(teleportee.getName());
if (teleporterName != null) {
if (teleporterName.equals("CONSOLE")) {
this.plugin.log(Level.FINER, "We know the teleporter is the console! Magical!");
Logging.finer("We know the teleporter is the console! Magical!");
teleporter = this.plugin.getServer().getConsoleSender();
} else {
teleporter = this.plugin.getServer().getPlayer(teleporterName);
teleporter = this.plugin.getServer().getPlayerExact(teleporterName);
}
}
this.plugin.log(Level.FINER, "Inferred sender '" + teleporter + "' from name '"
Logging.finer("Inferred sender '" + teleporter + "' from name '"
+ teleporterName + "', fetched from name '" + teleportee.getName() + "'");
MultiverseWorld fromWorld = this.worldManager.getMVWorld(event.getFrom().getWorld().getName());
MultiverseWorld toWorld = this.worldManager.getMVWorld(event.getTo().getWorld().getName());
if (toWorld == null) {
this.plugin.log(Level.FINE, "Player '" + teleportee.getName() + "' is teleporting to world '"
Logging.fine("Player '" + teleportee.getName() + "' is teleporting to world '"
+ event.getTo().getWorld().getName() + "' which is not managed by Multiverse-Core. No further "
+ "actions will be taken by Multiverse-Core.");
return;
}
if (event.getFrom().getWorld().equals(event.getTo().getWorld())) {
// The player is Teleporting to the same world.
this.plugin.log(Level.FINER, "Player '" + teleportee.getName() + "' is teleporting to the same world.");
Logging.finer("Player '" + teleportee.getName() + "' is teleporting to the same world.");
this.stateSuccess(teleportee.getName(), toWorld.getAlias());
return;
}
@@ -192,7 +201,7 @@ public class MVPlayerListener implements Listener {
// Charge the teleporter
event.setCancelled(!pt.playerHasMoneyToEnter(fromWorld, toWorld, teleporter, teleportee, true));
if (event.isCancelled() && teleporter != null) {
this.plugin.log(Level.FINE, "Player '" + teleportee.getName()
Logging.fine("Player '" + teleportee.getName()
+ "' was DENIED ACCESS to '" + toWorld.getAlias()
+ "' because '" + teleporter.getName()
+ "' don't have the FUNDS required to enter it.");
@@ -203,14 +212,14 @@ public class MVPlayerListener implements Listener {
if (plugin.getMVConfig().getEnforceAccess()) {
event.setCancelled(!pt.playerCanGoFromTo(fromWorld, toWorld, teleporter, teleportee));
if (event.isCancelled() && teleporter != null) {
this.plugin.log(Level.FINE, "Player '" + teleportee.getName()
Logging.fine("Player '" + teleportee.getName()
+ "' was DENIED ACCESS to '" + toWorld.getAlias()
+ "' because '" + teleporter.getName()
+ "' don't have: multiverse.access." + event.getTo().getWorld().getName());
return;
}
} else {
this.plugin.log(Level.FINE, "Player '" + teleportee.getName()
Logging.fine("Player '" + teleportee.getName()
+ "' was allowed to go to '" + toWorld.getAlias() + "' because enforceaccess is off.");
}
@@ -220,7 +229,7 @@ public class MVPlayerListener implements Listener {
if (toWorld.getCBWorld().getPlayers().size() >= toWorld.getPlayerLimit()) {
// Ouch the world is full, lets see if the player can bypass that limitation
if (!pt.playerCanBypassPlayerLimit(toWorld, teleporter, teleportee)) {
this.plugin.log(Level.FINE, "Player '" + teleportee.getName()
Logging.fine("Player '" + teleportee.getName()
+ "' was DENIED ACCESS to '" + toWorld.getAlias()
+ "' because the world is full and '" + teleporter.getName()
+ "' doesn't have: mv.bypass.playerlimit." + event.getTo().getWorld().getName());
@@ -235,7 +244,7 @@ public class MVPlayerListener implements Listener {
}
private void stateSuccess(String playerName, String worldName) {
this.plugin.log(Level.FINE, "MV-Core is allowing Player '" + playerName
Logging.fine("MV-Core is allowing Player '" + playerName
+ "' to go to '" + worldName + "'.");
}
@@ -282,12 +291,12 @@ public class MVPlayerListener implements Listener {
MultiverseWorld toWorld = this.worldManager.getMVWorld(event.getTo().getWorld().getName());
if (event.getFrom().getWorld().equals(event.getTo().getWorld())) {
// The player is Portaling to the same world.
this.plugin.log(Level.FINER, "Player '" + event.getPlayer().getName() + "' is portaling to the same world.");
Logging.finer("Player '" + event.getPlayer().getName() + "' is portaling to the same world.");
return;
}
event.setCancelled(!pt.playerHasMoneyToEnter(fromWorld, toWorld, event.getPlayer(), event.getPlayer(), true));
if (event.isCancelled()) {
this.plugin.log(Level.FINE, "Player '" + event.getPlayer().getName()
Logging.fine("Player '" + event.getPlayer().getName()
+ "' was DENIED ACCESS to '" + event.getTo().getWorld().getName()
+ "' because they don't have the FUNDS required to enter.");
return;
@@ -295,12 +304,12 @@ public class MVPlayerListener implements Listener {
if (plugin.getMVConfig().getEnforceAccess()) {
event.setCancelled(!pt.playerCanGoFromTo(fromWorld, toWorld, event.getPlayer(), event.getPlayer()));
if (event.isCancelled()) {
this.plugin.log(Level.FINE, "Player '" + event.getPlayer().getName()
Logging.fine("Player '" + event.getPlayer().getName()
+ "' was DENIED ACCESS to '" + event.getTo().getWorld().getName()
+ "' because they don't have: multiverse.access." + event.getTo().getWorld().getName());
}
} else {
this.plugin.log(Level.FINE, "Player '" + event.getPlayer().getName()
Logging.fine("Player '" + event.getPlayer().getName()
+ "' was allowed to go to '" + event.getTo().getWorld().getName()
+ "' because enforceaccess is off.");
}
@@ -311,7 +320,7 @@ public class MVPlayerListener implements Listener {
event.getPortalTravelAgent().setSearchRadius(plugin.getMVConfig().getPortalSearchRadius());
}
} catch (ClassNotFoundException ignore) {
plugin.log(Level.FINE, "TravelAgent not available for PlayerPortalEvent for " + event.getPlayer().getName());
Logging.fine("TravelAgent not available for PlayerPortalEvent for " + event.getPlayer().getName());
}
}
@@ -335,7 +344,7 @@ public class MVPlayerListener implements Listener {
if (mvWorld != null) {
this.handleGameModeAndFlight(player, mvWorld);
} else {
this.plugin.log(Level.FINER, "Not handling gamemode and flight for world '" + world.getName()
Logging.finer("Not handling gamemode and flight for world '" + world.getName()
+ "' not managed by Multiverse.");
}
}
@@ -376,7 +385,7 @@ public class MVPlayerListener implements Listener {
player.getName(), player.getWorld().getName(), world.getName());
}
} else {
MVPlayerListener.this.plugin.log(Level.FINE, "Player: " + player.getName() + " is IMMUNE to gamemode changes!");
Logging.fine("Player: " + player.getName() + " is IMMUNE to gamemode changes!");
}
}
}, 1L);
@@ -7,6 +7,7 @@
package com.onarandombox.MultiverseCore.listeners;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
import org.bukkit.Material;
@@ -56,7 +57,7 @@ public class MVPortalListener implements Listener {
public void portalForm(PortalCreateEvent event) {
MultiverseWorld world = this.plugin.getMVWorldManager().getMVWorld(event.getWorld());
if (world != null && !world.getAllowedPortals().isPortalAllowed(PortalType.NETHER)) {
plugin.log(Level.FINE, "Cancelling creation of nether portal because portalForm disallows.");
Logging.fine("Cancelling creation of nether portal because portalForm disallows.");
event.setCancelled(true);
}
}
@@ -79,7 +80,7 @@ public class MVPortalListener implements Listener {
}
MultiverseWorld world = this.plugin.getMVWorldManager().getMVWorld(event.getPlayer().getWorld());
if (world != null && !world.getAllowedPortals().isPortalAllowed(PortalType.ENDER)) {
plugin.log(Level.FINE, "Cancelling creation of ender portal because portalForm disallows.");
Logging.fine("Cancelling creation of ender portal because portalForm disallows.");
event.setCancelled(true);
}
}
@@ -74,7 +74,7 @@ public class AnchorManager {
this.anchorConfig.save(new File(this.plugin.getDataFolder(), "anchors.yml"));
return true;
} catch (IOException e) {
this.plugin.log(Level.SEVERE, "Failed to save anchors.yml. Please check your file permissions.");
Logging.severe("Failed to save anchors.yml. Please check your file permissions.");
return false;
}
}
@@ -2,6 +2,7 @@ package com.onarandombox.MultiverseCore.utils;
import java.util.logging.Level;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.destination.CannonDestination;
import org.bukkit.Location;
@@ -89,7 +90,7 @@ public class BukkitTravelAgent implements TravelAgent {
private Location getSafeLocation() {
// At this time, these can never use the velocity.
if (agent.destination instanceof CannonDestination) {
agent.core.log(Level.FINE, "Using Stock TP method. This cannon will have 0 velocity");
Logging.fine("Using Stock TP method. This cannon will have 0 velocity");
}
SafeTTeleporter teleporter = agent.core.getSafeTTeleporter();
Location newLoc = agent.destination.getLocation(agent.player);
@@ -0,0 +1,46 @@
package com.onarandombox.MultiverseCore.utils;
import com.dumptruckman.minecraft.util.Logging;
import org.bukkit.Bukkit;
import org.bukkit.event.player.PlayerRespawnEvent;
import java.lang.reflect.Method;
/**
* A utility class to enable version specific minecraft features.
*/
public class CompatibilityLayer {
private static Method checkAnchorSpawn;
/**
* Initialise the reflection methods.
*/
public static void init() {
try {
checkAnchorSpawn = PlayerRespawnEvent.class.getDeclaredMethod("isAnchorSpawn");
} catch (NoSuchMethodException e) {
Logging.fine("%s does not support respawn anchors.", Bukkit.getVersion());
}
}
/**
* Check if the respawn point is of respawn anchor type.
* Introduced in minecraft 1.16
*
* @param event A player respawn event.
* @return If the respawn location is an anchor point.
*/
public static boolean isAnchorSpawn(PlayerRespawnEvent event) {
if (checkAnchorSpawn == null) {
return false;
}
try {
return (boolean) checkAnchorSpawn.invoke(event);
} catch (Exception e) {
Logging.warning("Error checking for: %s", checkAnchorSpawn);
e.printStackTrace();
}
return false;
}
}
@@ -16,7 +16,9 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
@@ -70,19 +72,30 @@ public class FileUtils {
* Helper method to copy the world-folder.
* @param source Source-File
* @param target Target-File
* @param log A logger that logs the operation
*
* @return if it had success
* @return true if it had success
*/
public static boolean copyFolder(File source, File target, Logger log) {
public static boolean copyFolder(File source, File target) {
return copyFolder(source, target, null);
}
/**
* Helper method to copy the world-folder.
* @param source Source-File
* @param target Target-File
* @param excludeFiles files to ignore and not copy over to Target-File
*
* @return true if it had success
*/
public static boolean copyFolder(File source, File target, List<String> excludeFiles) {
Path sourceDir = source.toPath();
Path targetDir = target.toPath();
try {
Files.walkFileTree(sourceDir, new CopyDirFileVisitor(sourceDir, targetDir));
Files.walkFileTree(sourceDir, new CopyDirFileVisitor(sourceDir, targetDir, excludeFiles));
return true;
} catch (IOException e) {
log.log(Level.WARNING, "Unable to copy directory", e);
Logging.warning("Unable to copy directory", e);
return false;
}
}
@@ -91,10 +104,12 @@ public class FileUtils {
private final Path sourceDir;
private final Path targetDir;
private final List<String> excludeFiles;
private CopyDirFileVisitor(Path sourceDir, Path targetDir) {
private CopyDirFileVisitor(Path sourceDir, Path targetDir, List<String> excludeFiles) {
this.sourceDir = sourceDir;
this.targetDir = targetDir;
this.excludeFiles = excludeFiles;
}
@Override
@@ -108,9 +123,13 @@ public class FileUtils {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
// Pass files that are set to ignore
if (excludeFiles != null && excludeFiles.contains(file.getFileName().toString()))
return FileVisitResult.CONTINUE;
// Copy the files
Path targetFile = targetDir.resolve(sourceDir.relativize(file));
Files.copy(file, targetFile, COPY_ATTRIBUTES);
return FileVisitResult.CONTINUE;
}
}
}
}
@@ -7,6 +7,7 @@
package com.onarandombox.MultiverseCore.utils;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVDestination;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
@@ -100,7 +101,7 @@ public class MVPermissions implements PermissionsInterface {
public boolean canEnterWorld(Player p, MultiverseWorld w) {
// If we're not enforcing access, anyone can enter.
if (!plugin.getMVConfig().getEnforceAccess()) {
this.plugin.log(Level.FINEST, "EnforceAccess is OFF. Player was allowed in " + w.getAlias());
Logging.finest("EnforceAccess is OFF. Player was allowed in " + w.getAlias());
return true;
}
return this.hasPermission(p, "multiverse.access." + w.getName(), false);
@@ -257,14 +258,14 @@ public class MVPermissions implements PermissionsInterface {
boolean hasPermission = sender.hasPermission(node);
if (!sender.isPermissionSet(node)) {
this.plugin.log(Level.FINER, String.format("The node [%s%s%s] was %sNOT%s set for [%s%s%s].",
Logging.finer(String.format("The node [%s%s%s] was %sNOT%s set for [%s%s%s].",
ChatColor.RED, node, ChatColor.WHITE, ChatColor.RED, ChatColor.WHITE, ChatColor.AQUA,
player.getDisplayName(), ChatColor.WHITE));
}
if (hasPermission) {
this.plugin.log(Level.FINER, "Checking to see if player [" + player.getName() + "] has permission [" + node + "]... YES");
Logging.finer("Checking to see if player [" + player.getName() + "] has permission [" + node + "]... YES");
} else {
this.plugin.log(Level.FINER, "Checking to see if player [" + player.getName() + "] has permission [" + node + "]... NO");
Logging.finer("Checking to see if player [" + player.getName() + "] has permission [" + node + "]... NO");
}
return hasPermission;
}
@@ -7,6 +7,7 @@
package com.onarandombox.MultiverseCore.utils;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
import org.bukkit.Material;
@@ -195,7 +196,7 @@ public class PermissionTools {
* @return True if they can't go to the world, False if they can.
*/
public boolean playerCanGoFromTo(MultiverseWorld fromWorld, MultiverseWorld toWorld, CommandSender teleporter, Player teleportee) {
this.plugin.log(Level.FINEST, "Checking '" + teleporter + "' can send '" + teleportee + "' somewhere");
Logging.finest("Checking '" + teleporter + "' can send '" + teleportee + "' somewhere");
Player teleporterPlayer;
if (plugin.getMVConfig().getTeleportIntercept()) {
@@ -0,0 +1,176 @@
package com.onarandombox.MultiverseCore.utils;
import com.dumptruckman.minecraft.util.Logging;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Helper class to get {@link Player} from name, UUID or Selectors.
*/
public class PlayerFinder {
private static final Pattern UUID_REGEX = Pattern.compile("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}");
private static final Pattern COMMA_SPLIT = Pattern.compile(",");
/**
* Get a {@link Player} based on an identifier of name UUID or selector.
*
* @param playerIdentifier An identifier of name UUID or selector.
* @param sender Target sender for selector.
* @return The player if found, else null.
*/
@Nullable
public static Player get(@NotNull String playerIdentifier,
@NotNull CommandSender sender) {
Player targetPlayer = getByName(playerIdentifier);
if (targetPlayer != null) {
return targetPlayer;
}
targetPlayer = getByUuid(playerIdentifier);
if (targetPlayer != null) {
return targetPlayer;
}
return getBySelector(playerIdentifier, sender);
}
/**
* Get multiple {@link Player} based on many identifiers of name UUID or selector.
*
* @param playerIdentifiers An identifier of multiple names, UUIDs or selectors, separated by comma.
* @param sender Target sender for selector.
* @return A list of all the {@link Player} found.
*/
@Nullable
public static List<Player> getMulti(@NotNull String playerIdentifiers,
@NotNull CommandSender sender) {
String[] playerIdentifierArray = COMMA_SPLIT.split(playerIdentifiers);
if (playerIdentifierArray == null || playerIdentifierArray.length == 0) {
return null;
}
List<Player> playerResults = new ArrayList<>();
for (String playerIdentifier : playerIdentifierArray) {
Player targetPlayer = getByName(playerIdentifier);
if (targetPlayer != null) {
playerResults.add(targetPlayer);
continue;
}
targetPlayer = getByUuid(playerIdentifier);
if (targetPlayer != null) {
playerResults.add(targetPlayer);
continue;
}
List<Player> targetPlayers = getMultiBySelector(playerIdentifier, sender);
if (targetPlayers != null) {
playerResults.addAll(targetPlayers);
}
}
return playerResults;
}
/**
* Get a {@link Player} based on player name.
*
* @param playerName Name of a {@link Player}.
* @return The player if found, else null.
*/
@Nullable
public static Player getByName(@NotNull String playerName) {
return Bukkit.getPlayerExact(playerName);
}
/**
* Get a {@link Player} based on player UUID.
*
* @param playerUuid UUID of a player.
* @return The player if found, else null.
*/
@Nullable
public static Player getByUuid(@NotNull String playerUuid) {
if (!UUID_REGEX.matcher(playerUuid).matches()) {
return null;
}
UUID uuid;
try {
uuid = UUID.fromString(playerUuid);
} catch (Exception e) {
return null;
}
return getByUuid(uuid);
}
/**
* Get a {@link Player} based on playerUUID.
*
* @param playerUuid UUID of a player.
* @return The player if found, else null.
*/
@Nullable
public static Player getByUuid(@NotNull UUID playerUuid) {
return Bukkit.getPlayer(playerUuid);
}
/**
* Get a {@link Player} based on vanilla selectors.
* https://minecraft.gamepedia.com/Commands#Target_selectors
*
* @param playerSelector A target selector, usually starts with an '@'.
* @param sender Target sender for selector.
* @return The player if only one found, else null.
*/
@Nullable
public static Player getBySelector(@NotNull String playerSelector,
@NotNull CommandSender sender) {
List<Player> matchedPlayers = getMultiBySelector(playerSelector, sender);
if (matchedPlayers == null || matchedPlayers.isEmpty()) {
Logging.warning("No player found with selector '%s' for %s.", playerSelector, sender.getName());
return null;
}
if (matchedPlayers.size() > 1) {
Logging.warning("Ambiguous selector result '%s' for %s (more than one player matched) - %s",
playerSelector, sender.getName(), matchedPlayers.toString());
return null;
}
return matchedPlayers.get(0);
}
/**
* Get multiple {@link Player} based on selector.
* https://minecraft.gamepedia.com/Commands#Target_selectors
*
* @param playerSelector A target selector, usually starts with an '@'.
* @param sender Target sender for selector.
* @return A list of all the {@link Player} found.
*/
@Nullable
public static List<Player> getMultiBySelector(@NotNull String playerSelector,
@NotNull CommandSender sender) {
if (playerSelector.charAt(0) != '@') {
return null;
}
try {
return Bukkit.selectEntities(sender, playerSelector).stream()
.filter(e -> e instanceof Player)
.map(e -> ((Player) e))
.collect(Collectors.toList());
} catch (IllegalArgumentException e) {
Logging.warning("An error occurred while parsing selector '%s' for %s. Is it is the correct format?",
playerSelector, sender.getName());
e.printStackTrace();
return null;
}
}
}
@@ -7,6 +7,7 @@
package com.onarandombox.MultiverseCore.utils;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
@@ -86,7 +87,7 @@ public class PurgeWorlds {
}
int entitiesKilled = 0;
for (Entity e : world.getEntities()) {
this.plugin.log(Level.FINEST, "Entity list (aval for purge) from WORLD < " + mvworld.getName() + " >: " + e.toString());
Logging.finest("Entity list (aval for purge) from WORLD < " + mvworld.getName() + " >: " + e.toString());
// Check against Monsters
if (killMonster(mvworld, e, thingsToKill, negateMonsters)) {
@@ -133,16 +134,16 @@ public class PurgeWorlds {
entityName = e.toString().replaceAll("Craft", "").toUpperCase();
}
if (e instanceof Slime || e instanceof Monster || e instanceof Ghast || e instanceof EnderDragon) {
this.plugin.log(Level.FINEST, "Looking at a monster: " + e);
Logging.finest("Looking at a monster: " + e);
if (creaturesToKill.contains(entityName) || creaturesToKill.contains("ALL") || creaturesToKill.contains("MONSTERS")) {
if (!negate) {
this.plugin.log(Level.FINEST, "Removing a monster: " + e);
Logging.finest("Removing a monster: " + e);
e.remove();
return true;
}
} else {
if (negate) {
this.plugin.log(Level.FINEST, "Removing a monster: " + e);
Logging.finest("Removing a monster: " + e);
e.remove();
return true;
}
@@ -0,0 +1,140 @@
package com.onarandombox.MultiverseCore.utils;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* Utility class used to help in doing various reflection actions.
*/
public class ReflectHelper {
/**
* Try to get the {@link Class} based on its classpath.
*
* @param classPath The target classpath.
* @return A {@link Class} if found, else null.
*/
@Nullable
public static Class<?> getClass(String classPath) {
try {
return Class.forName(classPath);
} catch (ClassNotFoundException e) {
return null;
}
}
/**
* Check if the {@link Class} for a give classpath is present/valid.
*
* @param classPath Target classpath.
* @return True if class path is a valid class, else false.
*/
public static boolean hasClass(String classPath) {
return getClass(classPath) != null;
}
/**
* Try to get a {@link Method} from a given class.
*
* @param clazz The class to search the method on.
* @param methodName Name of the method to get.
* @param parameterTypes Parameters present for that method.
* @param <C> The class type.
* @return A {@link Method} if found, else null.
*/
@Nullable
public static <C> Method getMethod(Class<C> clazz, String methodName, Class<?>... parameterTypes) {
try {
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
return method;
} catch (NoSuchMethodException e) {
return null;
}
}
/**
* Try to get a {@link Method} from a given class.
*
* @param classInstance Instance of the class to search the method on.
* @param methodName Name of the method to get.
* @param parameterTypes Parameters present for that method.
* @param <C> The class type.
* @return A {@link Method} if found, else null.
*/
@Nullable
public static <C> Method getMethod(C classInstance, String methodName, Class<?>... parameterTypes) {
return getMethod(classInstance.getClass(), methodName, parameterTypes);
}
/**
* Calls a {@link Method}.
*
* @param classInstance Instance of the class responsible for the method.
* @param method The method to call.
* @param parameters Parameters needed when calling the method.
* @param <C> The class type.
* @param <R> The return type.
* @return Return value of the method call if any, else null.
*/
@Nullable
public static <C, R> R invokeMethod(C classInstance, Method method, Object...parameters) {
try {
return (R) method.invoke(classInstance, parameters);
} catch (Exception e) {
return null;
}
}
/**
* Try to get a {@link Field} from a given class.
*
* @param clazz The class to search the field on.
* @param fieldName Name of the field to get.
* @param <C> The class type.
* @return A {@link Field} if found, else null.
*/
@Nullable
public static <C> Field getField(Class<C> clazz, String fieldName) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
return null;
}
}
/**
* Try to get a {@link Field} from a given class.
*
* @param classInstance Instance of the class to search the field on.
* @param fieldName Name of the field to get.
* @param <C> The class type.
* @return A {@link Field} if found, else null.
*/
@Nullable
public static <C> Field getField(C classInstance, String fieldName) {
return getField(classInstance.getClass(), fieldName);
}
/**
* Gets the value of an {@link Field} from an instance of the class responsible.
*
* @param classInstance Instance of the class to get the field value from.
* @param field The field to get value from.
* @param <C> The class type.
* @param <V> The field value type.
* @return The field value if any, else null.
*/
@Nullable
public static <C, V> V getFieldValue(C classInstance, Field field) {
try {
return (V) field.get(classInstance);
} catch (IllegalAccessException e) {
return null;
}
}
}
@@ -19,6 +19,7 @@ import com.onarandombox.MultiverseCore.api.LocationManipulation;
import java.text.DecimalFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
@@ -39,6 +40,15 @@ public class SimpleLocationManipulation implements LocationManipulation {
orientationInts.put("w", 90);
orientationInts.put("nw", 135);
orientationInts.put("north", 180);
orientationInts.put("northeast", 225);
orientationInts.put("east", 270);
orientationInts.put("southeast", 315);
orientationInts.put("south", 0);
orientationInts.put("southwest", 45);
orientationInts.put("west", 90);
orientationInts.put("northwest", 135);
// "freeze" the map:
ORIENTATION_INTS = Collections.unmodifiableMap(orientationInts);
// END CHECKSTYLE-SUPPRESSION: MagicNumberCheck
@@ -52,7 +62,7 @@ public class SimpleLocationManipulation implements LocationManipulation {
if (location == null) {
return "";
}
return String.format("%s:%.2f,%.2f,%.2f:%.2f:%.2f", location.getWorld().getName(),
return String.format(Locale.ENGLISH, "%s:%.2f,%.2f,%.2f:%.2f:%.2f", location.getWorld().getName(),
location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
}
@@ -7,6 +7,7 @@
package com.onarandombox.MultiverseCore.utils;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.api.MVDestination;
@@ -58,9 +59,9 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
if (safe != null) {
safe.setX(safe.getBlockX() + .5); // SUPPRESS CHECKSTYLE: MagicNumberCheck
safe.setZ(safe.getBlockZ() + .5); // SUPPRESS CHECKSTYLE: MagicNumberCheck
this.plugin.log(Level.FINE, "Hey! I found one: " + plugin.getLocationManipulation().strCoordsRaw(safe));
Logging.fine("Hey! I found one: " + plugin.getLocationManipulation().strCoordsRaw(safe));
} else {
this.plugin.log(Level.FINE, "Uh oh! No safe place found!");
Logging.fine("Uh oh! No safe place found!");
}
return safe;
}
@@ -72,8 +73,8 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
}
// We want half of it, so we can go up and down
tolerance /= 2;
this.plugin.log(Level.FINER, "Given Location of: " + plugin.getLocationManipulation().strCoordsRaw(l));
this.plugin.log(Level.FINER, "Checking +-" + tolerance + " with a radius of " + radius);
Logging.finer("Given Location of: " + plugin.getLocationManipulation().strCoordsRaw(l));
Logging.finer("Checking +-" + tolerance + " with a radius of " + radius);
// For now this will just do a straight up block.
Location locToCheck = l.clone();
@@ -191,7 +192,7 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
@Override
public TeleportResult safelyTeleport(CommandSender teleporter, Entity teleportee, MVDestination d) {
if (d instanceof InvalidDestination) {
this.plugin.log(Level.FINER, "Entity tried to teleport to an invalid destination");
Logging.finer("Entity tried to teleport to an invalid destination");
return TeleportResult.FAIL_INVALID;
}
Player teleporteePlayer = null;
@@ -248,7 +249,7 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
public Location getSafeLocation(Entity e, MVDestination d) {
Location l = d.getLocation(e);
if (plugin.getBlockSafety().playerCanSpawnHereSafely(l)) {
plugin.log(Level.FINE, "The first location you gave me was safe.");
Logging.fine("The first location you gave me was safe.");
return l;
}
if (e instanceof Minecart) {
@@ -267,21 +268,21 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
// Add offset to account for a vehicle on dry land!
if (e instanceof Minecart && !plugin.getBlockSafety().isEntitiyOnTrack(safeLocation)) {
safeLocation.setY(safeLocation.getBlockY() + .5);
this.plugin.log(Level.FINER, "Player was inside a minecart. Offsetting Y location.");
Logging.finer("Player was inside a minecart. Offsetting Y location.");
}
this.plugin.log(Level.FINE, "Had to look for a bit, but I found a safe place for ya!");
Logging.finer("Had to look for a bit, but I found a safe place for ya!");
return safeLocation;
}
if (e instanceof Player) {
Player p = (Player) e;
this.plugin.getMessaging().sendMessage(p, "No safe locations found!", false);
this.plugin.log(Level.FINER, "No safe location found for " + p.getName());
Logging.finer("No safe location found for " + p.getName());
} else if (e.getPassenger() instanceof Player) {
Player p = (Player) e.getPassenger();
this.plugin.getMessaging().sendMessage(p, "No safe locations found!", false);
this.plugin.log(Level.FINER, "No safe location found for " + p.getName());
Logging.finer("No safe location found for " + p.getName());
}
this.plugin.log(Level.FINE, "Sorry champ, you're basically trying to teleport into a minefield. I should just kill you now.");
Logging.fine("Sorry champ, you're basically trying to teleport into a minefield. I should just kill you now.");
return null;
}
@@ -0,0 +1,18 @@
package com.onarandombox.MultiverseCore.utils;
/**
* A utility class that enables automated tests to flag Multiverse for testing. This allows Multiverse to not perform
* certain behaviors such as enabled stats uploads.
*/
public class TestingMode {
private static boolean enabled = false;
public static void enable() {
enabled = true;
}
public static boolean isDisabled() {
return !enabled;
}
}
@@ -36,8 +36,11 @@ import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
@@ -45,16 +48,19 @@ import java.util.Set;
import java.util.Stack;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Public facing API to add/remove Multiverse worlds.
*/
public class WorldManager implements MVWorldManager {
private final MultiverseCore plugin;
private final Pattern worldNamePattern = Pattern.compile("[a-zA-Z0-9/._-]+");
private final WorldPurger worldPurger;
private final Map<String, MultiverseWorld> worlds;
private Map<String, WorldProperties> worldsFromTheConfig;
private Set<String> defaultWorldNames;
private FileConfiguration configWorlds = null;
private Map<String, String> defaultGens;
private String firstSpawn;
@@ -87,7 +93,7 @@ public class WorldManager implements MVWorldManager {
}
}
} else {
this.plugin.log(Level.WARNING, "Could not read 'bukkit.yml'. Any Default worldgenerators will not be loaded!");
Logging.warning("Could not read 'bukkit.yml'. Any Default worldgenerators will not be loaded!");
}
}
@@ -125,12 +131,18 @@ public class WorldManager implements MVWorldManager {
return false;
}
// Check for valid world name
if (!(WorldNameChecker.isValidWorldName(oldName) && WorldNameChecker.isValidWorldName(oldName))) {
return false;
}
final File oldWorldFile = new File(this.plugin.getServer().getWorldContainer(), oldName);
final File newWorldFile = new File(this.plugin.getServer().getWorldContainer(), newName);
final List<String> ignoreFiles = new ArrayList<>(Arrays.asList("session.lock", "uid.dat"));
// Make sure the new world doesn't exist outside of multiverse.
if (newWorldFile.exists()) {
Logging.warning("File for new world '%s' already exists", newName);
Logging.warning("Folder for new world '%s' already exists", newName);
return false;
}
@@ -152,14 +164,8 @@ public class WorldManager implements MVWorldManager {
}
// Grab a bit of metadata from the old world.
MVWorld oldWorld = (MVWorld) getMVWorld(oldName);
Environment environment = oldWorld.getEnvironment();
String seedString = oldWorld.getSeed() + "";
WorldType worldType = oldWorld.getWorldType();
Boolean generateStructures = oldWorld.getCBWorld().canGenerateStructures();
String generator = oldWorld.getGenerator();
boolean useSpawnAdjust = oldWorld.getAdjustSpawn();
MultiverseWorld oldWorld = getMVWorld(oldName);
// Don't need the loaded world anymore.
if (wasJustLoaded) {
this.unloadWorld(oldName, true);
@@ -177,32 +183,40 @@ public class WorldManager implements MVWorldManager {
oldWorld.getCBWorld().save();
}
Logging.config("Copying files for world '%s'", oldName);
if (!FileUtils.copyFolder(oldWorldFile, newWorldFile, Logging.getLogger())) {
if (!FileUtils.copyFolder(oldWorldFile, newWorldFile, ignoreFiles)) {
Logging.warning("Failed to copy files for world '%s', see the log info", newName);
return false;
}
if (oldWorld != null && wasAutoSave) {
oldWorld.getCBWorld().setAutoSave(true);
}
if (newWorldFile.exists()) {
Logging.fine("Succeeded at copying files");
File uidFile = new File(newWorldFile, "uid.dat");
if (uidFile.exists() && !uidFile.delete()) {
Logging.warning("Failed to delete unique ID file for world '%s'", newName);
// initialize new properties with old ones
WorldProperties newProps = new WorldProperties();
newProps.copyValues(this.worldsFromTheConfig.get(oldName));
// don't keep the alias the same -- that would be useless
newProps.setAlias("");
// store the new properties in worlds config map
this.worldsFromTheConfig.put(newName, newProps);
// save the worlds config to disk (worlds.yml)
if (!saveWorldsConfig()) {
Logging.severe("Failed to save worlds.yml");
return false;
}
// actually load the world
if (doLoad(newName)) {
Logging.fine("Succeeded at loading cloned world '" + newName + "'");
return true;
}
Logging.severe("Failed to load the cloned world '" + newName + "'");
return false;
}
if (newWorldFile.exists()) {
Logging.fine("Succeeded at copying files");
if (this.addWorld(newName, environment, seedString, worldType, generateStructures, generator, useSpawnAdjust)) {
// getMVWorld() doesn't actually return an MVWorld
Logging.fine("Succeeded at importing world");
MVWorld newWorld = (MVWorld) this.getMVWorld(newName);
newWorld.copyValues(this.worldsFromTheConfig.get(oldName));
// don't keep the alias the same -- that would be useless
newWorld.setAlias(null);
return true;
}
}
Logging.warning("Failed to copy files for world '%s', see the log info", newName);
return false;
}
@@ -225,6 +239,13 @@ public class WorldManager implements MVWorldManager {
if (name.equalsIgnoreCase("plugins") || name.equalsIgnoreCase("logs")) {
return false;
}
if (!WorldNameChecker.isValidWorldName(name)) {
Logging.warning("Invalid world name '" + name + "'");
Logging.warning("World name should not contain spaces or special characters!");
return false;
}
Long seed = null;
WorldCreator c = new WorldCreator(name);
if (seedString != null && seedString.length() > 0) {
@@ -267,7 +288,7 @@ public class WorldManager implements MVWorldManager {
Logging.info(builder.toString());
if (!doLoad(c, true)) {
this.plugin.log(Level.SEVERE, "Failed to Create/Load the world '" + name + "'");
Logging.severe("Failed to Create/Load the world '" + name + "'");
return false;
}
@@ -340,7 +361,7 @@ public class WorldManager implements MVWorldManager {
MultiverseWorld world = this.getMVWorld(this.firstSpawn);
if (world == null) {
// If the spawn world was unloaded, get the default world
this.plugin.log(Level.WARNING, "The world specified as the spawn world (" + this.firstSpawn + ") did not exist!!");
Logging.warning("The world specified as the spawn world (" + this.firstSpawn + ") did not exist!!");
try {
return this.getMVWorld(this.plugin.getServer().getWorlds().get(0));
} catch (IndexOutOfBoundsException e) {
@@ -364,6 +385,11 @@ public class WorldManager implements MVWorldManager {
*/
@Override
public boolean unloadWorld(String name, boolean unloadBukkit) {
if (this.isDefaultWorld(name)) {
Logging.warning("You cannot unload the default worlds.");
Logging.warning("Default worlds on your server are: %s", this.defaultWorldNames);
return false;
}
if (this.worlds.containsKey(name)) {
this.worldsFromTheConfig.get(name).cacheVirtualProperties();
if (unloadBukkit && this.unloadWorldFromBukkit(name, true)) {
@@ -408,15 +434,15 @@ public class WorldManager implements MVWorldManager {
}
private void brokenWorld(String name) {
this.plugin.log(Level.SEVERE, "The world '" + name + "' could NOT be loaded because it contains errors and is probably corrupt!");
this.plugin.log(Level.SEVERE, "Try using Minecraft Region Fixer to repair your world! '" + name + "'");
this.plugin.log(Level.SEVERE, "https://github.com/Fenixin/Minecraft-Region-Fixer");
Logging.severe("The world '" + name + "' could NOT be loaded because it contains errors and is probably corrupt!");
Logging.severe("Try using Minecraft Region Fixer to repair your world! '" + name + "'");
Logging.severe("https://github.com/Fenixin/Minecraft-Region-Fixer");
}
private void nullWorld(String name) {
this.plugin.log(Level.SEVERE, "The world '" + name + "' could NOT be loaded because the server didn't like it!");
this.plugin.log(Level.SEVERE, "We don't really know why this is. Contact the developer of your server software!");
this.plugin.log(Level.SEVERE, "Server version info: " + Bukkit.getServer().getVersion());
Logging.severe("The world '" + name + "' could NOT be loaded because the server didn't like it!");
Logging.severe("We don't really know why this is. Contact the developer of your server software!");
Logging.severe("Server version info: " + Bukkit.getServer().getVersion());
}
private boolean doLoad(String name) {
@@ -456,8 +482,8 @@ public class WorldManager implements MVWorldManager {
throw new IllegalArgumentException("That world is already loaded!");
if (!ignoreExists && !new File(this.plugin.getServer().getWorldContainer(), worldName).exists() && !new File(this.plugin.getServer().getWorldContainer().getParent(), worldName).exists()) {
this.plugin.log(Level.WARNING, "WorldManager: Can't load this world because the folder was deleted/moved: " + worldName);
this.plugin.log(Level.WARNING, "Use '/mv remove' to remove it from the config!");
Logging.warning("WorldManager: Can't load this world because the folder was deleted/moved: " + worldName);
Logging.warning("Use '/mv remove' to remove it from the config!");
return false;
}
@@ -487,6 +513,13 @@ public class WorldManager implements MVWorldManager {
*/
@Override
public boolean deleteWorld(String name, boolean removeFromConfig, boolean deleteWorldFolder) {
if (this.hasUnloadedWorld(name, false)) {
// Attempt to load if unloaded so we can actually delete the world
if (!this.doLoad(name)) {
return false;
}
}
World world = this.plugin.getServer().getWorld(name);
if (world == null) {
// We can only delete loaded worlds
@@ -497,7 +530,7 @@ public class WorldManager implements MVWorldManager {
MVWorldDeleteEvent mvwde = new MVWorldDeleteEvent(getMVWorld(name), removeFromConfig);
this.plugin.getServer().getPluginManager().callEvent(mvwde);
if (mvwde.isCancelled()) {
this.plugin.log(Level.FINE, "Tried to delete a world, but the event was cancelled!");
Logging.fine("Tried to delete a world, but the event was cancelled!");
return false;
}
@@ -513,7 +546,7 @@ public class WorldManager implements MVWorldManager {
try {
File worldFile = world.getWorldFolder();
plugin.log(Level.FINER, "deleteWorld(): worldFile: " + worldFile.getAbsolutePath());
Logging.finer("deleteWorld(): worldFile: " + worldFile.getAbsolutePath());
if (deleteWorldFolder ? FileUtils.deleteFolder(worldFile) : FileUtils.deleteFolderContents(worldFile)) {
Logging.info("World '%s' was DELETED.", name);
return true;
@@ -591,6 +624,14 @@ public class WorldManager implements MVWorldManager {
*/
@Override
public MultiverseWorld getMVWorld(String name) {
return this.getMVWorld(name, true);
}
/**
* {@inheritDoc}
*/
@Override
public MultiverseWorld getMVWorld(String name, boolean checkAliases) {
if (name == null) {
return null;
}
@@ -598,7 +639,7 @@ public class WorldManager implements MVWorldManager {
if (world != null) {
return world;
}
return this.getMVWorldByAlias(name);
return (checkAliases) ? this.getMVWorldByAlias(name) : null;
}
/**
@@ -607,7 +648,7 @@ public class WorldManager implements MVWorldManager {
@Override
public MultiverseWorld getMVWorld(World world) {
if (world != null) {
return this.getMVWorld(world.getName());
return this.getMVWorld(world.getName(), false);
}
return null;
}
@@ -632,7 +673,15 @@ public class WorldManager implements MVWorldManager {
*/
@Override
public boolean isMVWorld(final String name) {
return (this.worlds.containsKey(name) || isMVWorldAlias(name));
return this.isMVWorld(name, true);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isMVWorld(final String name, boolean checkAliases) {
return this.worlds.containsKey(name) || (checkAliases && this.isMVWorldAlias(name));
}
/**
@@ -665,6 +714,7 @@ public class WorldManager implements MVWorldManager {
public void loadDefaultWorlds() {
this.ensureConfigIsPrepared();
List<World> myWorlds = this.plugin.getServer().getWorlds();
this.defaultWorldNames = new HashSet<>(myWorlds.size());
for (World w : myWorlds) {
String name = w.getName();
if (!worldsFromTheConfig.containsKey(name)) {
@@ -672,9 +722,15 @@ public class WorldManager implements MVWorldManager {
if (this.defaultGens.containsKey(name)) {
generator = this.defaultGens.get(name);
}
this.addWorld(name, w.getEnvironment(), String.valueOf(w.getSeed()), w.getWorldType(), w.canGenerateStructures(), generator);
if (!this.addWorld(name, w.getEnvironment(), String.valueOf(w.getSeed()), w.getWorldType(), w.canGenerateStructures(), generator)) {
Logging.warning("Error loading default world '%s'!", w.getName());
continue;
}
}
this.defaultWorldNames.add(name);
}
this.defaultWorldNames = Collections.unmodifiableSet(this.defaultWorldNames);
Logging.fine("Loaded default worlds: %s", this.defaultWorldNames);
}
private void ensureConfigIsPrepared() {
@@ -684,6 +740,21 @@ public class WorldManager implements MVWorldManager {
}
}
@Override
public boolean isDefaultWorld(MultiverseWorld world) {
return world != null && this.isDefaultWorld(world.getName());
}
@Override
public boolean isDefaultWorld(String worldName) {
return this.defaultWorldNames != null && this.defaultWorldNames.contains(worldName);
}
@Override
public Collection<String> getDefaultWorldNames() {
return this.defaultWorldNames;
}
/**
* {@inheritDoc}
*/
@@ -827,7 +898,7 @@ public class WorldManager implements MVWorldManager {
this.configWorlds.save(new File(this.plugin.getDataFolder(), "worlds.yml"));
return true;
} catch (IOException e) {
this.plugin.log(Level.SEVERE, "Could not save worlds.yml. Please check your settings.");
Logging.severe("Could not save worlds.yml. Please check your settings.");
return false;
}
}
@@ -899,6 +970,9 @@ public class WorldManager implements MVWorldManager {
return this.configWorlds;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasUnloadedWorld(String name, boolean includeLoaded) {
if (getMVWorld(name) != null) {
@@ -911,4 +985,21 @@ public class WorldManager implements MVWorldManager {
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public Collection<String> getPotentialWorlds() {
File worldContainer = this.plugin.getServer().getWorldContainer();
if (worldContainer == null) {
return Collections.emptyList();
}
return Arrays.stream(worldContainer.listFiles())
.filter(File::isDirectory)
.filter(folder -> !this.isMVWorld(folder.getName(), false))
.filter(WorldNameChecker::isValidWorldFolder)
.map(File::getName)
.collect(Collectors.toList());
}
}
@@ -0,0 +1,159 @@
package com.onarandombox.MultiverseCore.utils;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
/**
* <p>Utility class in helping to check the status of a world name and it's associated world folder.</p>
*
* <p>Note this is for preliminary checks and better command output. A valid result will suggest but not
* 100% determine that a world name can be created, loaded or imported.</p>
*/
public class WorldNameChecker {
private static final Pattern WORLD_NAME_PATTERN = Pattern.compile("[a-zA-Z0-9/._-]+");
private static final Set<String> BLACKLIST_NAMES = Collections.unmodifiableSet(new HashSet<String>() {{
add("plugins");
add("logs");
add("cache");
add("crash-reports");
}});
/**
* Checks if a world name is valid.
*
* @param worldName The world name to check on.
* @return True if check result is valid, else false.
*/
public static boolean isValidWorldName(@Nullable String worldName) {
return checkName(worldName) == NameStatus.VALID;
}
/**
* Checks the current validity status of a world name.
*
* @param worldName The world name to check on.
* @return The resulting name status.
*/
@NotNull
public static NameStatus checkName(@Nullable String worldName) {
if (BLACKLIST_NAMES.contains(worldName)) {
return NameStatus.BLACKLISTED;
}
if (worldName == null || !WORLD_NAME_PATTERN.matcher(worldName).matches()) {
return NameStatus.INVALID_CHARS;
}
return NameStatus.VALID;
}
/**
* Checks if a world name has a valid world folder.
*
* @param worldName The world name to check on.
* @return True if check result is valid, else false.
*/
public static boolean isValidWorldFolder(@Nullable String worldName) {
return checkFolder(worldName) == FolderStatus.VALID;
}
/**
* Checks if a world folder is valid.
*
* @param worldFolder The world folder to check on.
* @return True if check result is valid, else false.
*/
public static boolean isValidWorldFolder(@Nullable File worldFolder) {
return checkFolder(worldFolder) == FolderStatus.VALID;
}
/**
* Checks the current folder status for a world name.
*
* @param worldName The world name to check on.
* @return The resulting folder status.
*/
@NotNull
public static FolderStatus checkFolder(@Nullable String worldName) {
if (worldName == null) {
return FolderStatus.DOES_NOT_EXIST;
}
File worldFolder = new File(Bukkit.getWorldContainer(), worldName);
return checkFolder(worldFolder);
}
/**
* Checks the current folder status.
*
* @param worldFolder The world folder to check on.
* @return The resulting folder status.
*/
@NotNull
public static FolderStatus checkFolder(@Nullable File worldFolder) {
if (worldFolder == null || !worldFolder.exists() || !worldFolder.isDirectory()) {
return FolderStatus.DOES_NOT_EXIST;
}
if (!folderHasDat(worldFolder)) {
return FolderStatus.NOT_A_WORLD;
}
return FolderStatus.VALID;
}
/**
* A very basic check to see if a folder has a level.dat file. If it does, we can safely assume
* it's a world folder.
*
* @param worldFolder The File that may be a world.
* @return True if it looks like a world, else false.
*/
private static boolean folderHasDat(@NotNull File worldFolder) {
File[] files = worldFolder.listFiles((file, name) -> name.toLowerCase().endsWith(".dat"));
return files != null && files.length > 0;
}
/**
* Result after checking validity of world name.
*/
public enum NameStatus {
/**
* Name is valid.
*/
VALID,
/**
* Name not valid as it contains invalid characters.
*/
INVALID_CHARS,
/**
* Name not valid as it is deemed blacklisted.
*/
BLACKLISTED
}
/**
* Result after checking validity of world folder.
*/
public enum FolderStatus {
/**
* Folder is valid.
*/
VALID,
/**
* Folder exist, but contents in it doesnt look like a world.
*/
NOT_A_WORLD,
/**
* Folder does not exist.
*/
DOES_NOT_EXIST
}
}
@@ -0,0 +1,95 @@
package com.onarandombox.MultiverseCore.utils.metrics;
import java.util.Collection;
import java.util.Map;
import java.util.function.Consumer;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
import org.apache.commons.lang.WordUtils;
import org.bstats.bukkit.Metrics;
import org.bukkit.World;
public class MetricsConfigurator {
private static final int PLUGIN_ID = 7765;
private static final String NO_GENERATOR_NAME = "N/A";
public static void configureMetrics(MultiverseCore plugin) {
MetricsConfigurator configurator = new MetricsConfigurator(plugin);
configurator.initMetrics();
}
private final MultiverseCore plugin;
private final Metrics metrics;
private MetricsConfigurator(MultiverseCore plugin) {
this.plugin = plugin;
this.metrics = new Metrics(plugin, PLUGIN_ID);
}
private MVWorldManager getWorldManager() {
return plugin.getMVWorldManager();
}
private Collection<MultiverseWorld> getMVWorlds() {
return getWorldManager().getMVWorlds();
}
private void initMetrics() {
try {
addCustomGeneratorsMetric();
addEnvironmentsMetric();
addWorldCountMetric();
Logging.fine("Metrics enabled.");
} catch (Exception e) {
Logging.warning("There was an issue while enabling metrics:");
e.printStackTrace();
}
}
private void addCustomGeneratorsMetric() {
addAdvancedPieMetric("custom_generators", map -> {
for (MultiverseWorld w : getMVWorlds()) {
MetricsHelper.incrementCount(map, getGeneratorName(w));
}
});
}
private String getGeneratorName(MultiverseWorld world) {
String gen = world.getGenerator();
return (gen != null && !gen.equalsIgnoreCase("null")) ? gen.split(":")[0] : NO_GENERATOR_NAME;
}
private void addEnvironmentsMetric() {
addAdvancedPieMetric("environments", map -> {
for (MultiverseWorld w : getMVWorlds()) {
MetricsHelper.incrementCount(map, titleCaseEnv(w.getEnvironment()));
}
});
}
private String titleCaseEnv(World.Environment env) {
String envName = env.name().replaceAll("_+", " ");
return WordUtils.capitalizeFully(envName);
}
private void addWorldCountMetric() {
addMultiLineMetric("world_count", map -> {
int loadedWorldsCount = getMVWorlds().size();
map.put("Loaded worlds", loadedWorldsCount);
map.put("Total number of worlds", loadedWorldsCount + getWorldManager().getUnloadedWorlds().size());
});
}
private void addAdvancedPieMetric(String chartId, Consumer<Map<String, Integer>> metricsFunc) {
metrics.addCustomChart(MetricsHelper.createAdvancedPieChart(chartId, metricsFunc));
}
private void addMultiLineMetric(String chartId, Consumer<Map<String, Integer>> metricsFunc) {
metrics.addCustomChart(MetricsHelper.createMultiLineChart(chartId, metricsFunc));
}
}
@@ -0,0 +1,32 @@
package com.onarandombox.MultiverseCore.utils.metrics;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import org.bstats.bukkit.Metrics;
enum MetricsHelper {
;
/**
* Adds one to the value in the given map with the given key. If the key does not exist in the map, it will be added with a value of 1.
*/
static void incrementCount(Map<String, Integer> map, String key) {
Integer count = map.getOrDefault(key, 0);
map.put(key, count + 1);
}
static Metrics.AdvancedPie createAdvancedPieChart(String chartId, Consumer<Map<String, Integer>> metricsFunc) {
Map<String, Integer> map = new HashMap<>();
metricsFunc.accept(map);
return new Metrics.AdvancedPie(chartId, () -> map);
}
static Metrics.MultiLineChart createMultiLineChart(String chartId, Consumer<Map<String, Integer>> metricsFunc) {
Map<String, Integer> map = new HashMap<>();
metricsFunc.accept(map);
return new Metrics.MultiLineChart(chartId, () -> map);
}
}
@@ -1,19 +1,43 @@
package com.onarandombox.MultiverseCore.utils.webpaste;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.IOException;
import java.util.Map;
/**
* An {@link URLShortener} using {@code bit.ly}.
* A {@link URLShortener} using {@code bit.ly}. Requires an access token.
*/
public class BitlyURLShortener extends HttpAPIClient implements URLShortener {
private static final String GENERIC_BITLY_REQUEST_FORMAT = "https://api-ssl.bitly.com/v3/shorten?format=txt&apiKey=%s&login=%s&longUrl=%s";
class BitlyURLShortener extends URLShortener {
private static final String ACCESS_TOKEN = "Bearer bitly-access-token";
private static final String BITLY_POST_REQUEST = "https://api-ssl.bitly.com/v4/shorten";
// I think it's no problem that these are public
private static final String USERNAME = "multiverse2";
private static final String API_KEY = "R_9dbff4862a3bc0c4218a7d78cc10d0e0";
BitlyURLShortener() {
super(BITLY_POST_REQUEST, ACCESS_TOKEN);
if (ACCESS_TOKEN.endsWith("access-token")) {
throw new UnsupportedOperationException();
}
}
public BitlyURLShortener() {
super(String.format(GENERIC_BITLY_REQUEST_FORMAT, API_KEY, USERNAME, "%s"));
/**
* {@inheritDoc}
*/
@Override
String encodeData(String data) {
JSONObject json = new JSONObject();
json.put("domain", "j.mp");
json.put("long_url", data);
return json.toJSONString();
}
/**
* {@inheritDoc}
*/
@Override
String encodeData(Map<String, String> data) {
throw new UnsupportedOperationException();
}
/**
@@ -22,13 +46,11 @@ public class BitlyURLShortener extends HttpAPIClient implements URLShortener {
@Override
public String shorten(String longUrl) {
try {
String result = this.exec(longUrl);
if (!result.startsWith("http://j.mp/")) // ... then it's failed :/
throw new IOException(result);
return result;
} catch (IOException e) {
String stringJSON = this.exec(encodeData(longUrl), ContentType.JSON);
return (String) ((JSONObject) new JSONParser().parse(stringJSON)).get("link");
} catch (IOException | ParseException e) {
e.printStackTrace();
return longUrl; // sorry ...
return longUrl;
}
}
}
@@ -0,0 +1,90 @@
package com.onarandombox.MultiverseCore.utils.webpaste;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Pastes to {@code gist.github.com}. Requires an access token with the {@code gist} scope.
*/
class GitHubPasteService extends PasteService {
private final boolean isPrivate;
// this access token must have the "gist" scope
private static final String ACCESS_TOKEN = "token github-access-token";
private static final String GITHUB_POST_REQUEST = "https://api.github.com/gists";
GitHubPasteService(boolean isPrivate) {
super(GITHUB_POST_REQUEST, ACCESS_TOKEN);
this.isPrivate = isPrivate;
if (ACCESS_TOKEN.endsWith("access-token")) {
throw new UnsupportedOperationException();
}
}
/**
* {@inheritDoc}
*/
@Override
String encodeData(String data) {
Map<String, String> mapData = new HashMap<String, String>();
mapData.put("multiverse.txt", data);
return this.encodeData(mapData);
}
/**
* {@inheritDoc}
*/
@Override
String encodeData(Map<String, String> files) {
JSONObject root = new JSONObject();
root.put("description", "Multiverse-Core Debug Info");
root.put("public", !this.isPrivate);
JSONObject fileList = new JSONObject();
for (Map.Entry<String, String> entry : files.entrySet()) {
JSONObject fileObject = new JSONObject();
fileObject.put("content", entry.getValue());
fileList.put(entry.getKey(), fileObject);
}
root.put("files", fileList);
return root.toJSONString();
}
/**
* {@inheritDoc}
*/
@Override
public String postData(String data) throws PasteFailedException {
try {
String stringJSON = this.exec(encodeData(data), ContentType.JSON);
return (String) ((JSONObject) new JSONParser().parse(stringJSON)).get("html_url");
} catch (IOException | ParseException e) {
throw new PasteFailedException(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public String postData(Map<String, String> data) throws PasteFailedException {
try {
String stringJSON = this.exec(encodeData(data), ContentType.JSON);
return (String) ((JSONObject) new JSONParser().parse(stringJSON)).get("html_url");
} catch (IOException | ParseException e) {
throw new PasteFailedException(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean supportsMultiFile() {
return true;
}
}
@@ -1,99 +0,0 @@
package com.onarandombox.MultiverseCore.utils.webpaste;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
public class GithubPasteService implements PasteService {
private final boolean isPrivate;
public GithubPasteService(boolean isPrivate) {
this.isPrivate = isPrivate;
}
@Override
public String encodeData(String data) {
Map<String, String> mapData = new HashMap<String, String>();
mapData.put("multiverse.txt", data);
return this.encodeData(mapData);
}
@Override
public String encodeData(Map<String, String> files) {
JsonObject root = new JsonObject();
root.add("description", new JsonPrimitive("Multiverse-Core Debug Info"));
root.add("public", new JsonPrimitive(!this.isPrivate));
JsonObject fileList = new JsonObject();
for (Map.Entry<String, String> entry : files.entrySet())
{
JsonObject fileObject = new JsonObject();
fileObject.add("content", new JsonPrimitive(entry.getValue()));
fileList.add(entry.getKey(), fileObject);
}
root.add("files", fileList);
return root.toString();
}
@Override
public URL getPostURL() {
try {
return new URL("https://api.github.com/gists");
//return new URL("http://jsonplaceholder.typicode.com/posts");
} catch (MalformedURLException e) {
return null; // should never hit here
}
}
@Override
public String postData(String encodedData, URL url) throws PasteFailedException {
OutputStreamWriter wr = null;
BufferedReader rd = null;
try {
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(encodedData);
wr.flush();
rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
String pastieUrl = "";
//Pattern pastiePattern = this.getURLMatchingPattern();
StringBuilder responseString = new StringBuilder();
while ((line = rd.readLine()) != null) {
responseString.append(line);
}
return new JsonParser().parse(responseString.toString()).getAsJsonObject().get("html_url").getAsString();
} catch (Exception e) {
throw new PasteFailedException(e);
} finally {
if (wr != null) {
try {
wr.close();
} catch (IOException ignore) { }
}
if (rd != null) {
try {
rd.close();
} catch (IOException ignore) { }
}
}
}
@Override
public boolean supportsMultiFile() {
return true;
}
}
@@ -1,79 +1,67 @@
package com.onarandombox.MultiverseCore.utils.webpaste;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;
/**
* Pastes to {@code hastebin.com}.
*/
public class HastebinPasteService implements PasteService {
class HastebinPasteService extends PasteService {
private static final String HASTEBIN_POST_REQUEST = "https://hastebin.com/documents";
HastebinPasteService() {
super(HASTEBIN_POST_REQUEST);
}
/**
* {@inheritDoc}
*/
@Override
public String encodeData(String data) {
String encodeData(String data) {
return data;
}
/**
* {@inheritDoc}
*/
@Override
public String encodeData(Map<String, String> data) {
String encodeData(Map<String, String> data) {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
@Override
public URL getPostURL() {
public String postData(String data) throws PasteFailedException {
try {
return new URL("https://hastebin.com/documents");
} catch (MalformedURLException e) {
return null; // should never hit here
}
}
@Override
public String postData(String encodedData, URL url) throws PasteFailedException {
OutputStreamWriter wr = null;
BufferedReader rd = null;
try {
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
wr = new OutputStreamWriter(conn.getOutputStream());
rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
wr.write(encodedData);
wr.flush();
String line;
StringBuilder responseString = new StringBuilder();
while ((line = rd.readLine()) != null) {
responseString.append(line);
}
String key = new JsonParser().parse(responseString.toString()).getAsJsonObject().get("key").getAsString();
return "https://hastebin.com/" + key;
} catch (Exception e) {
String stringJSON = this.exec(encodeData(data), ContentType.PLAINTEXT);
return "https://hastebin.com/" + ((JSONObject) new JSONParser().parse(stringJSON)).get("key");
} catch (IOException | ParseException e) {
throw new PasteFailedException(e);
} finally {
if (wr != null) {
try {
wr.close();
} catch (IOException ignore) { }
}
if (rd != null) {
try {
rd.close();
} catch (IOException ignore) { }
}
}
}
/**
* {@inheritDoc}
*/
@Override
public String postData(Map<String, String> data) throws PasteFailedException {
try {
String stringJSON = this.exec(encodeData(data), ContentType.PLAINTEXT);
return "https://hastebin.com/" + ((JSONObject) new JSONParser().parse(stringJSON)).get("key");
} catch (IOException | ParseException e) {
throw new PasteFailedException(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean supportsMultiFile() {
return false;
@@ -1,50 +1,129 @@
package com.onarandombox.MultiverseCore.utils.webpaste;
import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* HTTP API-client.
*/
public abstract class HttpAPIClient {
abstract class HttpAPIClient {
/**
* The URL for this API-request.
* The URL for this API-request, and if necessary, the access token.
* If an access token is not necessary, it should be set to null.
*/
protected final String urlFormat;
private final String url;
private final String accessToken;
public HttpAPIClient(String urlFormat) {
this.urlFormat = urlFormat;
/**
* Types of data that can be sent.
*/
enum ContentType {
JSON,
PLAINTEXT,
URLENCODED
}
HttpAPIClient(String url) {
this(url, null);
}
HttpAPIClient(String url, String accessToken) {
this.url = url;
this.accessToken = accessToken;
}
/**
* Returns the HTTP Content-Type header that corresponds with each ContentType.
* @param type The type of data.
* @return The HTTP Content-Type header that corresponds with the type of data.
*/
private String getContentHeader(ContentType type) {
switch (type) {
case JSON:
return "application/json; charset=utf-8";
case PLAINTEXT:
return "text/plain; charset=utf-8";
case URLENCODED:
return "application/x-www-form-urlencoded; charset=utf-8";
default:
throw new IllegalArgumentException("Unexpected value: " + type);
}
}
/**
* Encode the given String data into a format suitable for transmission in an HTTP request.
*
* @param data The raw data to encode.
* @return A URL-encoded string.
*/
abstract String encodeData(String data);
/**
* Encode the given Map data into a format suitable for transmission in an HTTP request.
*
* @param data The raw data to encode.
* @return A URL-encoded string.
*/
abstract String encodeData(Map<String, String> data);
/**
* Executes this API-Request.
* @param args Format-args.
* @param payload The data that will be sent.
* @param type The type of data that will be sent.
* @return The result (as text).
* @throws IOException When the I/O-operation failed.
*/
protected final String exec(Object... args) throws IOException {
final String exec(String payload, ContentType type) throws IOException {
BufferedReader rd = null;
OutputStreamWriter wr = null;
URLConnection conn = new URL(String.format(this.urlFormat, args)).openConnection();
conn.connect();
StringBuilder ret = new StringBuilder();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while (!reader.ready()); // wait until reader is ready, may not be necessary, SUPPRESS CHECKSTYLE: EmptyStatement
HttpsURLConnection conn = (HttpsURLConnection) new URL(this.url).openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
while (reader.ready()) {
ret.append(reader.readLine()).append('\n');
// we can receive anything!
conn.addRequestProperty("Accept", "*/*");
// set a dummy User-Agent
conn.addRequestProperty("User-Agent", "placeholder");
// this isn't required, but is technically correct
conn.addRequestProperty("Content-Type", getContentHeader(type));
// only some API requests require an access token
if (this.accessToken != null) {
conn.addRequestProperty("Authorization", this.accessToken);
}
wr = new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8.newEncoder());
wr.write(payload);
wr.flush();
String line;
StringBuilder responseString = new StringBuilder();
// this has to be initialized AFTER the data has been flushed!
rd = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
while ((line = rd.readLine()) != null) {
responseString.append(line);
}
return responseString.toString();
} finally {
if (reader != null) {
if (wr != null) {
try {
reader.close();
wr.close();
} catch (IOException ignore) { }
}
if (rd != null) {
try {
rd.close();
} catch (IOException ignore) { }
}
}
return ret.toString();
}
}
@@ -1,7 +1,7 @@
package com.onarandombox.MultiverseCore.utils.webpaste;
/**
* Thrown when pasting failed.
* Thrown when pasting fails.
*/
public class PasteFailedException extends Exception {
public PasteFailedException() {
@@ -0,0 +1,90 @@
package com.onarandombox.MultiverseCore.utils.webpaste;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Pastes to {@code paste.gg}.
*/
class PasteGGPasteService extends PasteService {
private final boolean isPrivate;
private static final String PASTEGG_POST_REQUEST = "https://api.paste.gg/v1/pastes";
PasteGGPasteService(boolean isPrivate) {
super(PASTEGG_POST_REQUEST);
this.isPrivate = isPrivate;
}
/**
* {@inheritDoc}
*/
@Override
String encodeData(String data) {
Map<String, String> mapData = new HashMap<String, String>();
mapData.put("multiverse.txt", data);
return this.encodeData(mapData);
}
/**
* {@inheritDoc}
*/
@Override
String encodeData(Map<String, String> files) {
JSONObject root = new JSONObject();
root.put("name", "Multiverse-Core Debug Info");
root.put("visibility", this.isPrivate ? "unlisted" : "public");
JSONArray fileList = new JSONArray();
for (Map.Entry<String, String> entry : files.entrySet()) {
JSONObject fileObject = new JSONObject();
JSONObject contentObject = new JSONObject();
fileObject.put("name", entry.getKey());
fileObject.put("content", contentObject);
contentObject.put("format", "text");
contentObject.put("value", entry.getValue());
fileList.add(fileObject);
}
root.put("files", fileList);
return root.toJSONString();
}
/**
* {@inheritDoc}
*/
@Override
public String postData(String data) throws PasteFailedException {
try {
String stringJSON = this.exec(encodeData(data), ContentType.JSON);
return (String) ((JSONObject) ((JSONObject) new JSONParser().parse(stringJSON)).get("result")).get("id");
} catch (IOException | ParseException e) {
throw new PasteFailedException(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public String postData(Map<String, String> data) throws PasteFailedException {
try {
String stringJSON = this.exec(encodeData(data), ContentType.JSON);
return "https://paste.gg/" + ((JSONObject) ((JSONObject) new JSONParser().parse(stringJSON)).get("result")).get("id");
} catch (IOException | ParseException e) {
throw new PasteFailedException(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean supportsMultiFile() {
return true;
}
}
@@ -1,63 +1,52 @@
package com.onarandombox.MultiverseCore.utils.webpaste;
import java.net.URL;
import java.util.Map;
/**
* An interface to a web-based text-pasting service. Classes implementing this
* interface should implement its methods to send data to an online text-sharing
* service, such as pastebin.com. Conventionally, a paste is accomplished by (given
* some PasteService instance ps):
* An interface to a web-based text-pasting service. Classes extending this
* should implement its methods to send data to an online text-sharing service,
* such as pastebin.com. Given some PasteService instance ps, a paste is accomplished by:
*
* {@code ps.postData(ps.encodeData(someString), ps.getPostURL());}
* {@code ps.postData(someString);}
*
* Services that provide a distinction between "public" and "private" pastes
* should implement a custom constructor that specifies which kind the PasteService
* should implement a constructor that specifies which kind the PasteService
* instance is submitting; an example of this is the PastebinPasteService class.
*/
public interface PasteService {
public abstract class PasteService extends HttpAPIClient {
PasteService(String url) {
super(url);
}
PasteService(String url, String accessToken) {
super(url, accessToken);
}
/**
* Encode the given String data into a format suitable for transmission in an HTTP request.
* Post data to the Web.
*
* @param data The raw data to encode.
* @return A URL-encoded string.
*/
String encodeData(String data);
/**
* Encode the given Map data into a format suitable for transmission in an HTTP request.
*
* @param data The raw data to encode.
* @return A URL-encoded string.
*/
String encodeData(Map<String, String> data);
/**
* Get the URL to which this paste service sends new pastes.
*
* @return The URL that will be accessed to complete the paste.
*/
URL getPostURL();
/**
* Post encoded data to the Web.
*
* @param encodedData A URL-encoded String containing the full request to post to
* the given URL. Can be the result of calling #encodeData().
* @param url The URL to which to paste. Can be the result of calling #getPostURL().
* @param data A String to post to the web.
* @throws PasteFailedException When pasting/posting the data failed.
* @return The URL at which the new paste is visible.
*/
String postData(String encodedData, URL url) throws PasteFailedException;
public abstract String postData(String data) throws PasteFailedException;
/**
* Post data to the Web.
*
* @param data A Map to post to the web.
* @throws PasteFailedException When pasting/posting the data failed.
* @return The URL at which the new paste is visible.
*/
public abstract String postData(Map<String, String> data) throws PasteFailedException;
/**
* Does this service support uploading multiple files.
*
* Newer services like gist support multi-file which allows us to upload configs
* in addition to the standard logs.
* Newer services like GitHub's Gist support multi-file pastes,
* which allows us to upload configs in addition to the standard logs.
*
* @return True if this service supports multiple file upload.
*/
boolean supportsMultiFile();
public abstract boolean supportsMultiFile();
}
@@ -14,12 +14,14 @@ public class PasteServiceFactory {
*/
public static PasteService getService(PasteServiceType type, boolean isPrivate) {
switch(type) {
case PASTEGG:
return new PasteGGPasteService(isPrivate);
case PASTEBIN:
return new PastebinPasteService(isPrivate);
case HASTEBIN:
return new HastebinPasteService();
case GITHUB:
return new GithubPasteService(isPrivate);
return new GitHubPasteService(isPrivate);
default:
return null;
}
@@ -7,6 +7,10 @@ package com.onarandombox.MultiverseCore.utils.webpaste;
* @see PasteServiceFactory
*/
public enum PasteServiceType {
/**
* @see PasteGGPasteService
*/
PASTEGG,
/**
* @see PastebinPasteService
*/
@@ -16,7 +20,7 @@ public enum PasteServiceType {
*/
HASTEBIN,
/**
* @see GithubPasteService
* @see GitHubPasteService
*/
GITHUB
}
@@ -1,24 +1,19 @@
package com.onarandombox.MultiverseCore.utils.webpaste;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Map;
/**
* Pastes to {@code pastebin.com}.
*/
public class PastebinPasteService implements PasteService {
class PastebinPasteService extends PasteService {
private final boolean isPrivate;
private static final String PASTEBIN_POST_REQUEST = "https://pastebin.com/api/api_post.php";
private boolean isPrivate;
public PastebinPasteService(boolean isPrivate) {
PastebinPasteService(boolean isPrivate) {
super(PASTEBIN_POST_REQUEST);
this.isPrivate = isPrivate;
}
@@ -26,73 +21,54 @@ public class PastebinPasteService implements PasteService {
* {@inheritDoc}
*/
@Override
public URL getPostURL() {
String encodeData(String data) {
try {
return new URL("http://pastebin.com/api/api_post.php");
} catch (MalformedURLException e) {
return null; // should never hit here
}
}
/**
* {@inheritDoc}
*/
@Override
public String encodeData(String data) {
try {
String encData = URLEncoder.encode("api_dev_key", "UTF-8") + "=" + URLEncoder.encode("d61d68d31e8e0392b59b50b277411c71", "UTF-8");
encData += "&" + URLEncoder.encode("api_option", "UTF-8") + "=" + URLEncoder.encode("paste", "UTF-8");
encData += "&" + URLEncoder.encode("api_paste_code", "UTF-8") + "=" + URLEncoder.encode(data, "UTF-8");
encData += "&" + URLEncoder.encode("api_paste_private", "UTF-8") + "=" + URLEncoder.encode(this.isPrivate ? "1" : "0", "UTF-8");
encData += "&" + URLEncoder.encode("api_paste_format", "UTF-8") + "=" + URLEncoder.encode("yaml", "UTF-8");
return encData;
return URLEncoder.encode("api_dev_key", "UTF-8") + "=" + URLEncoder.encode("d61d68d31e8e0392b59b50b277411c71", "UTF-8") +
"&" + URLEncoder.encode("api_option", "UTF-8") + "=" + URLEncoder.encode("paste", "UTF-8") +
"&" + URLEncoder.encode("api_paste_code", "UTF-8") + "=" + URLEncoder.encode(data, "UTF-8") +
"&" + URLEncoder.encode("api_paste_private", "UTF-8") + "=" + URLEncoder.encode(this.isPrivate ? "1" : "0", "UTF-8") +
"&" + URLEncoder.encode("api_paste_format", "UTF-8") + "=" + URLEncoder.encode("yaml", "UTF-8") +
"&" + URLEncoder.encode("api_paste_name", "UTF-8") + "=" + URLEncoder.encode("Multiverse-Core Debug Info", "UTF-8");
} catch (UnsupportedEncodingException e) {
return ""; // should never hit here
}
}
/**
* {@inheritDoc}
*/
@Override
public String encodeData(Map<String, String> data) {
return null;
String encodeData(Map<String, String> data) {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
@Override
public String postData(String encodedData, URL url) throws PasteFailedException {
OutputStreamWriter wr = null;
BufferedReader rd = null;
public String postData(String data) throws PasteFailedException {
try {
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(encodedData);
wr.flush();
rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
String pastebinUrl = "";
while ((line = rd.readLine()) != null) {
pastebinUrl = line;
}
return pastebinUrl;
} catch (Exception e) {
return this.exec(encodeData(data), ContentType.URLENCODED);
} catch (IOException e) {
throw new PasteFailedException(e);
} finally {
if (wr != null) {
try {
wr.close();
} catch (IOException ignore) { }
}
if (rd != null) {
try {
rd.close();
} catch (IOException ignore) { }
}
}
}
/**
* {@inheritDoc}
*/
@Override
public String postData(Map<String, String> data) throws PasteFailedException {
try {
return this.exec(encodeData(data), ContentType.URLENCODED);
} catch (IOException e) {
throw new PasteFailedException(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean supportsMultiFile() {
return false;
@@ -1,13 +1,27 @@
package com.onarandombox.MultiverseCore.utils.webpaste;
/**
* URL-Shortener.
* An interface to a web-based URL Shortener. Classes extending this should
* implement its methods to shorten links using the service. Given some
* URLShortener instance us, a URL is shortened by:
*
* {@code us.shorten(longUrl);}
*
* An example of this, is the BitlyURLShortener.
*/
public interface URLShortener {
public abstract class URLShortener extends HttpAPIClient {
URLShortener(String url) {
super(url);
}
URLShortener(String url, String accessToken) {
super(url, accessToken);
}
/**
* Shorten an URL.
* Shorten a URL.
* @param longUrl The long form.
* @return The shortened URL.
*/
String shorten(String longUrl);
public abstract String shorten(String longUrl);
}
@@ -0,0 +1,23 @@
package com.onarandombox.MultiverseCore.utils.webpaste;
/**
* Used to construct {@link URLShortener}s.
*/
public class URLShortenerFactory {
private URLShortenerFactory() { }
/**
* Constructs a new {@link URLShortener}.
* @param type The {@link URLShortenerType}.
* @return The newly created {@link URLShortener}.
*/
public static URLShortener getService(URLShortenerType type) {
if (type == URLShortenerType.BITLY) {
try {
return new BitlyURLShortener();
} catch (UnsupportedOperationException ignored) {}
}
return null;
}
}
@@ -0,0 +1,14 @@
package com.onarandombox.MultiverseCore.utils.webpaste;
/**
* An enum containing all known {@link URLShortener}s.
*
* @see URLShortener
* @see URLShortenerFactory
*/
public enum URLShortenerType {
/**
* @see BitlyURLShortener
*/
BITLY
}
+64 -113
View File
@@ -1,7 +1,8 @@
name: Multiverse-Core
main: com.onarandombox.MultiverseCore.MultiverseCore
authors: ['Rigby', 'fernferret', 'lithium3141', 'main--', 'dumptruckman']
authors: ['dumptruckman', 'Rigby', 'fernferret', 'lithium3141', 'main--']
website: 'https://dev.bukkit.org/projects/multiverse-core'
softdepend: ['Vault']
api-version: 1.13
version: maven-version-number
commands:
@@ -10,34 +11,24 @@ commands:
usage: /<command>
mvcreate:
description: World create command
usage: |
/<command> <world> <environment>
/<command> creative normal -- Creates a world called 'creative' with a NORMAL environment.
/<command> hellworld nether -- Creates a world called 'hellworld' with a NETHER environment.
mvc:
description: World create command
aliases: [mvc]
usage: |
/<command> <world> <environment>
/<command> creative normal -- Creates a world called 'creative' with a NORMAL environment.
/<command> hellworld nether -- Creates a world called 'hellworld' with a NETHER environment.
mvimport:
description: World import command
aliases: [mvim]
usage: |
/<command> <world> <environment>
/<command> creative normal -- Imports an existing world called 'creative' with a NORMAL environment.
/<command> hellworld nether -- Imports an existing world called 'hellworld' with a NETHER environment.
mvim:
description: World import command
usage: |
/<command> <world> <environment>
/<command> creative normal -- Imports an existing world called 'creative' with a NORMAL environment.
/<command> hellworld nether -- Imports an existing world called 'hellworld' with a NETHER environment.
/<command> <world> <environment> [-g generator[:id]] [-n]
/<command> creative normal -- Imports an existing world called 'creative' with a NORMAL environment.
/<command> hellworld nether -- Imports an existing world called 'hellworld' with a NETHER environment.
mvremove:
description: World remove command
description: Remove world from multiverse command
usage: |
/<command> <world>
mvdelete:
description: World delete command
description: Delete world from server folders command
usage: |
/<command> <world>
mvunload:
@@ -46,103 +37,75 @@ commands:
/<command> <world>
mvmodify:
description: Modify the settings of an existing world
aliases: [mvm]
usage: |
/<command> <world> <option>:<value>
/<command> creative pvp:false -- Turns off PVP in the 'creative' world.
/<command> <set|add|remove|clear> <value> <property> [world]
/<command> set pvp false creative -- Turns off PVP in the 'creative' world.
mvmset:
description: Modify the settings of an existing world
usage: |
/<command> <world> <option>:<value>
/<command> creative pvp:false -- Turns off PVP in the 'creative' world.
/<command> <value> <property> [world]
/<command> pvp false creative -- Turns off PVP in the 'creative' world.
mvmadd:
description: Modify the settings of an existing world
usage: |
/<command> <world> <option>:<value>
/<command> creative pvp:false -- Turns off PVP in the 'creative' world.
/<command> <value> <property> [world]
/<command> sheep animals world_nether -- Add sheep to animal list for 'world_nether' world.
mvmremove:
description: Modify the settings of an existing world
aliases: [mvmdelete]
usage: |
/<command> <world> <option>:<value>
/<command> creative pvp:false -- Turns off PVP in the 'creative' world.
/<command> <value> <property> [world]
/<command> sheep animals world_nether -- remove sheep from animal list for 'world_nether' world.
mvmclear:
description: Modify the settings of an existing world
usage: |
/<command> <world> <option>:<value>
/<command> creative pvp:false -- Turns off PVP in the 'creative' world.
mvm:
description: Modify the settings of an existing world
usage: |
/<command> <world> <option>:<value>
/<command> creative pvp:false -- Turns off PVP in the 'creative' world.
/<command> <property> [world]
/<command> animals world_nether -- Empties animal list for 'world_nether' world.
mvtp:
description: Command to teleport between Worlds
usage: |
/<command> <world>[:spawn]
/<command> [player] <destination>
Example: /<command> creative - Teleports you to the relevant location in the 'creative' world.
Example: /<command> creative:spawn - Teleports you to the spawn of the 'creative' world.
mvlist:
description: Print list of loaded Worlds
aliases: [mvl]
usage: |
/<command> [environment]
Example: /<command> NETHER - Shows all NETHER Worlds.
Example: /<command> NORMAL - Shows all NORMAL Worlds.
mvl:
description: Print list of loaded Worlds
usage: |
/<command> [environment]
/<command> [page]
Example: /<command> NETHER - Shows all NETHER Worlds.
Example: /<command> NORMAL - Shows all NORMAL Worlds.
mvsetspawn:
description: Set the spawn area for a particular world
usage: /<command> -- Sets the spawn area of the current world to your location.
mvset:
description: Set the spawn area for a particular world
usage: /<command> -- Sets the spawn area of the current world to your location.
mvss:
description: Set the spawn area for a particular world
aliases: [mvsets, mvss]
usage: /<command> -- Sets the spawn area of the current world to your location.
mvspawn:
description: Teleport to the spawn area
usage: /<command> -- Teleports you to the spawn area of your current world.
mvs:
description: Teleport to the spawn area
usage: /<command> -- Teleports you to the spawn area of your current world.
aliases: [mvs]
usage: /<command> [player] -- Teleports you to the spawn area of your current world.
mvcoord:
description: Display World, Coordinates, Direction & Compression for a world.
usage: |
/<command> [world]
/<command> -- Shows the relevant coordinates in your current world.
/<command> creative -- Shows the relevant coordinates if you were in the 'creative' world.
mvc:
description: Display World, Coordinates, Direction & Compression for a world.
aliases: [mvco]
usage: |
/<command> [world]
/<command> -- Shows the relevant coordinates in your current world.
/<command> creative -- Shows the relevant coordinates if you were in the 'creative' world.
mvwho:
description: Display online users per world.
aliases: [mvw]
usage: |
/<command> [world]
/<command> -- Shows who is online in each world.
/<command> creative -- Shows who is online in the 'creative' world.
mvw:
description: Display online users per world.
usage: |
/<command> [world]
/<command> [world|--all]
/<command> -- Shows who is online in each world.
/<command> creative -- Shows who is online in the 'creative' world.
mvreload:
description: Reload Configuration files.
usage: /<command>
mvr:
description: Reload Configuration files.
aliases: [mvr]
usage: /<command>
mvpurge:
description: Purge the targetted world of creatures.
usage: |
/<command> [world] [creatures]
/<command> [WORLD|all] [all|animals|monsters|MOBNAME]
/<command> -- Purges the players world of all creatures.
/<command> creative * -- Purges the creative world of all Creatures.
/<command> creative all -- Purges the creative world of all Creatures.
/<command> creative creeper -- Purges the creative world of all CREEPERS.
mvconfirm:
description: Confirms sensitive decisions like deleting a world.
@@ -150,87 +113,75 @@ commands:
/<command>
mvinfo:
description: Gets world info.
aliases: [mvi]
usage: |
/<command> [world]
mvi:
description: Gets world info.
usage: |
/<command> [world]
/<command> [world] [page]
mvenv:
description: Tells the user all possible environment types.
usage: |
/<command>
mvv:
description: Prints out version info.
usage: |
/<command>
mvversion:
description: Prints out version info.
aliases: [mvv, mvver]
usage: |
/<command>
mvco:
description: Displays the player's coordinates.
usage: |
/<command>
mvh:
description: Displays the Multiverse Help.
usage: |
/<command>
mvsearch:
description: Displays the Multiverse Help.
usage: |
/<command>
/<command> [-b|-h|-p] [--include-plugin-list]
mvhelp:
description: Displays the Multiverse Help.
aliases: [mvsearch, mvh]
usage: |
/<command>
/<command> [filter] [page #]
mvdebug:
description: Turns on debugging.
usage: |
/<command>
/<command> [1|2|3|off|silent]
mvgenerators:
description: Displays all found world generators.
usage: |
/<command>
mvgens:
description: Displays all found world generators.
aliases: [mvgens]
usage: |
/<command>
mvload:
description: Loads a world into Multiverse.
usage: |
/<command> {WORLD}
/<command> <world>
mvregen:
description: Regenerates a world Multiverse already knows about.
usage: |
/<command> {WORLD}
/<command> <world> [-s seed]
mvscript:
description: Runs a script from the Multiverse scripts directory.
usage: |
/<command> {script} [target]
/<command> <script> [target]
mvclone:
description: World clone command
aliases: [mvcl]
usage: |
/<command> <world> <environment>
/<command> <world> <environment> [-g generator[:id]]
/<command> creative grieftastic -- Creates a world called 'grieftastic' exactly identical to the world 'creative'.
mvsilent:
description: Reduces startup messages
usage: |
/<command> [true|false]
mvgamerule:
description: Sets a gamerule.
aliases: [mvrule]
usage: |
/<command> {RULE} {VALUE} [WORLD]
mvrule:
description: Sets a gamerule.
usage: |
/<command> {RULE} {VALUE} [WORLD]
/<command> <rule> <value> [world]
mvgamerules:
description: Lists the gamerules.
description: Lists the gamerules
aliases: [mvrules]
usage: |
/<command> [WORLD]
mvrules:
description: Lists the gamerules.
/<command> [world]
mvanchors:
description: Creating and removing Anchors command
aliases: [mvanchor]
usage: |
/<command> [WORLD]
/<command> <name> [-d]
mvcheck:
description: Validate your multiverse settings command
usage: |
/<command> <name> <destination>
mvconfig:
description: Configuration command
aliases: [mvconf]
usage: |
/<command> <property> <value>
@@ -50,6 +50,10 @@ public class TestEntryFeeConversion {
WorldProperties props = new WorldProperties(config);
assertNull(props.entryfee.getCurrency());
entryFee.put("currency", 0);
props = new WorldProperties(config);
assertNull(props.entryfee.getCurrency());
entryFee.put("currency", 1);
props = new WorldProperties(config);
assertEquals(Material.STONE, props.entryfee.getCurrency());
@@ -6,6 +6,9 @@ import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.dumptruckman.minecraft.util.Logging;
import org.junit.After;
@@ -78,7 +81,7 @@ public class FileUtilsTest {
assertFalse(Files.isDirectory(targetChildDir));
assertFalse(Files.isRegularFile(targetChildDirFile));
assertTrue(FileUtils.copyFolder(parentDir.toFile(), targetDir.toFile(), Logging.getLogger()));
assertTrue(FileUtils.copyFolder(parentDir.toFile(), targetDir.toFile()));
assertTrue(Files.isDirectory(targetDir));
assertTrue(Files.isRegularFile(targetFile));
@@ -86,6 +89,34 @@ public class FileUtilsTest {
assertTrue(Files.isRegularFile(targetChildDirFile));
}
@Test
public void copyFolder_excludingSomeFiles() throws Exception {
Path targetDir = tempDir.resolve("target");
Path targetFile = targetDir.resolve("parentDirFile.txt");
Path targetIgnoreFile = targetDir.resolve("parentIgnoreFile.txt");
Path targetChildDir = targetDir.resolve("childDir");
Path targetChildDirFile = targetChildDir.resolve("childDirFile.txt");
Path targetChildIgnoreFile = targetChildDir.resolve("childIgnoreFile.txt");
List<String> excludeFiles = new ArrayList<>(Arrays.asList("parentIgnoreFile.txt", "childIgnoreFile.txt"));
assertFalse(Files.isDirectory(targetDir));
assertFalse(Files.isRegularFile(targetFile));
assertFalse(Files.isRegularFile(targetIgnoreFile));
assertFalse(Files.isDirectory(targetChildDir));
assertFalse(Files.isRegularFile(targetChildDirFile));
assertFalse(Files.isRegularFile(targetChildIgnoreFile));
assertTrue(FileUtils.copyFolder(parentDir.toFile(), targetDir.toFile(), excludeFiles));
assertTrue(Files.isDirectory(targetDir));
assertTrue(Files.isRegularFile(targetFile));
assertFalse(Files.isRegularFile(targetIgnoreFile));
assertTrue(Files.isDirectory(targetChildDir));
assertTrue(Files.exists(targetChildDirFile));
assertFalse(Files.isRegularFile(targetChildIgnoreFile));
}
@Test
public void copyFolder_intoExistingFolder() throws Exception {
Path targetDir = Files.createDirectory(tempDir.resolve("target"));
@@ -98,7 +129,7 @@ public class FileUtilsTest {
assertFalse(Files.isDirectory(targetChildDir));
assertFalse(Files.isRegularFile(targetChildDirFile));
assertTrue(FileUtils.copyFolder(parentDir.toFile(), targetDir.toFile(), Logging.getLogger()));
assertTrue(FileUtils.copyFolder(parentDir.toFile(), targetDir.toFile()));
assertTrue(Files.isDirectory(targetDir));
assertTrue(Files.isRegularFile(targetFile));
@@ -114,6 +145,6 @@ public class FileUtilsTest {
assertTrue(Files.isDirectory(targetDir));
assertTrue(Files.isRegularFile(targetFile));
assertFalse(FileUtils.copyFolder(parentDir.toFile(), targetDir.toFile(), Logging.getLogger()));
assertFalse(FileUtils.copyFolder(parentDir.toFile(), targetDir.toFile()));
}
}
@@ -64,6 +64,7 @@ public class TestInstanceCreator {
public static final File worldsDirectory = new File("bin/test/server");
public boolean setUp() {
TestingMode.enable();
try {
pluginDirectory.mkdirs();
assertTrue(pluginDirectory.exists());
@@ -213,11 +214,18 @@ public class TestInstanceCreator {
serverfield.set(core, mockServer);
// Set buscript
Buscript buscript = PowerMockito.spy(new Buscript(core));
Buscript buscript;
Field buscriptfield = MultiverseCore.class.getDeclaredField("buscript");
buscriptfield.setAccessible(true);
try {
buscript = PowerMockito.spy(new Buscript(core));
when(buscript.getPlugin()).thenReturn(core);
} catch (NullPointerException e) {
buscript = null;
}
buscriptfield.set(core, buscript);
when(buscript.getPlugin()).thenReturn(core);
// Set worldManager
WorldManager wm = PowerMockito.spy(new WorldManager(core));