Compare commits

..
53 Commits
Author SHA1 Message Date
benwoo1110 74089df9a1 Implement new GeneratorManager system. 2021-03-09 19:46:03 +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
53 changed files with 1677 additions and 294 deletions

No files matched your search

+2 -2
View File
@@ -2,7 +2,7 @@
name: ❓ Help!
about: Encountered a problem with Multiverse-Core? Not sure how to fix it?
title: ''
labels: 'type: Assistance'
labels: 'Type: Assistance'
assignees: ''
---
@@ -40,7 +40,7 @@ If you're happy to wait (or you were sent here from Discord), read on:
* **Server version:** <!-- Insert output of `/version` command -->
* **Full output of `/mv version -b`:** <!-- Replace this with the command output's https://pastebin.com link -->
* **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/ -->
+2 -2
View File
@@ -2,7 +2,7 @@
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: 'type: Bug'
labels: 'Bug: Unconfirmed'
assignees: ''
---
@@ -39,7 +39,7 @@ If you are reporting a bug, please follow the following steps:
* **Server version:** <!-- Insert output of `/version` command -->
* **Full output of `/mv version -b`:** <!-- Replace this with the command output's https://pastebin.com link -->
* **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/ -->
+1 -1
View File
@@ -2,7 +2,7 @@
name: 💡 Request a Feature
about: Suggest a feature you want to see in Multiverse-Core!
title: ''
labels: 'type: Suggestion'
labels: 'Type: Idea'
assignees: ''
---
+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.
+13 -7
View File
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.onarandombox.multiversecore</groupId>
<artifactId>Multiverse-Core</artifactId>
<version>4.2.0</version>
<version>4.2.3-SNAPSHOT</version>
<name>Multiverse-Core</name>
<description>World Management Plugin</description>
<properties>
@@ -215,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>
@@ -264,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>
@@ -319,7 +325,7 @@
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>1.7</version>
<version>1.8</version>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
@@ -353,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!!!");
}
}
}
@@ -77,6 +77,8 @@ import com.onarandombox.MultiverseCore.destination.PlayerDestination;
import com.onarandombox.MultiverseCore.destination.WorldDestination;
import com.onarandombox.MultiverseCore.event.MVDebugModeEvent;
import com.onarandombox.MultiverseCore.event.MVVersionEvent;
import com.onarandombox.MultiverseCore.generators.GeneratorManager;
import com.onarandombox.MultiverseCore.api.MVGeneratorManager;
import com.onarandombox.MultiverseCore.listeners.MVAsyncPlayerChatListener;
import com.onarandombox.MultiverseCore.listeners.MVChatListener;
import com.onarandombox.MultiverseCore.listeners.MVEntityListener;
@@ -88,11 +90,13 @@ 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;
@@ -211,6 +215,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
// Configurations
private FileConfiguration multiverseConfig = null;
private MVGeneratorManager generatorManager;
private final MVWorldManager worldManager = new WorldManager(this);
// Setup the block/player/entity listener.
@@ -253,6 +258,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();
}
@@ -276,7 +283,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
this.messaging = new MVMessaging();
this.economist = new MVEconomist(this);
// Load the defaultWorldGenerators
this.worldManager.getDefaultWorldGenerators();
this.generatorManager = new GeneratorManager(this);
this.registerEvents();
// Setup Permissions, we'll do an initial check for the Permissions plugin then fall back on isOP().
@@ -305,7 +312,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();
@@ -343,20 +350,25 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
}
private void setupMetrics() {
MetricsConfigurator.configureMetrics(this);
if (TestingMode.isDisabled()) {
MetricsConfigurator.configureMetrics(this);
}
}
/**
* Initializes the buscript javascript library.
*/
private void initializeBuscript() {
try {
buscript = new Buscript(this);
// Add global variable "multiverse" to javascript environment
buscript.setScriptVariable("multiverse", this);
} catch (NullPointerException e) {
buscript = null;
Logging.warning("Buscript failed to load! The script command will be disabled!");
buscript = null;
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!");
}
}
}
@@ -380,7 +392,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);
}
@@ -499,13 +511,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;
}
@@ -518,7 +530,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();
@@ -684,8 +696,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) {
@@ -702,7 +714,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;
}
@@ -836,8 +848,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);
}
@@ -1001,6 +1017,14 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
this.serverFolder = newServerFolder;
}
/**
* {@inheritDoc}
*/
@Override
public MVGeneratorManager getMVGeneratorManager() {
return generatorManager;
}
/**
* {@inheritDoc}
*/
@@ -1056,7 +1080,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;
}
}
@@ -56,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;
@@ -99,6 +101,7 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements
teleportintercept = true;
firstspawnoverride = true;
displaypermerrors = true;
enablebuscript = true;
globaldebug = 0;
messagecooldown = 5000;
teleportcooldown = 1000;
@@ -213,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}
*/
@@ -94,6 +94,13 @@ public interface Core {
*/
DestinationFactory getDestFactory();
/**
* Gets the class responsible for managing world generators plugins installed on the server.
*
* @return A valid {@link MVGeneratorManager}.
*/
MVGeneratorManager getMVGeneratorManager();
/**
* Gets the primary class responsible for managing Multiverse Worlds.
*
@@ -0,0 +1,101 @@
package com.onarandombox.MultiverseCore.api;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
/**
* <p>A generator API for Multiverse.</p>
*
* <p>Any generator plugin can register themselves to Multiverse. This will provide Multiverse with addition
* information about your generator plugin such as generator id suggestions, example usages and link to more
* info on your generator plugin.</p>
*
* <p>To register your plugin, implement this class and see {@link MVGeneratorManager#register(GeneratorPlugin)}.</p>
*/
public interface GeneratorPlugin {
/**
* <p>Suggest possible generator ids. To be used in command tab-completion.</p>
*
* <p>These suggestions can be static without relying on currentIdInput, or dynamically changed based
* on the currentIdInput.</p>
*
* @param currentIdInput The current state user input. This may be null or empty if user has not started
* any input for generator id.
* @return Collection of suggested generator ids.
*/
@NotNull
Collection<String> suggestIds(@Nullable String currentIdInput);
/**
* <p>Gets a default or any valid {@link ChunkGenerator}.</p>
*
* <p>This is used on {@link MVGeneratorManager#register(GeneratorPlugin)} to prove to Multiverse that
* you are a valid generator plugin. If this returns null or throw an exception, your generator plugin
* will not be registered.</p>
*
* @return A {@link ChunkGenerator} if possible, else null.
* @throws Exception When an error occurs in getting {@link ChunkGenerator}.
*/
@Nullable
ChunkGenerator getDefaultChunkGenerator() throws Exception;
/**
* <p>Gets a chunk generator based on a world name and id specified.</p>
*
* <p>If this returns null or throw an exception, it will indicate to Multiverse that there is either an issue
* with your plugin, or the generator id given is invalid.</p>
*
* @param id Target generator id.
* @param worldName Target world name to use generator on.
* @return A {@link ChunkGenerator} if possible, else null.
* @throws Exception When an error occurs in getting a {@link ChunkGenerator}.
*/
@Nullable
ChunkGenerator getChunkGenerator(String id, String worldName) throws Exception;
/**
* <p>Gets command usages that users can try to generate a world with your generator plugin. Returning null means
* you do not wish to show any usage examples for your generator plugin.</p>
*
* <p>An example command: '/mv create myworld normal -g CoolGen:FunWorld'</p>
*
* <p>Notes on usage of this method:</p>
* <ul>
* <li>Feel free to have colors in your command usage, but not Multiverse won't parse color codes for you.</li>
* <li>Please include the starting slash '/' in your usage examples.</li>
* <li>We suggest keeping the usage to at most 5 examples.</li>
* <li>This should not be a full explanation on all your generator plugin, just basics usages to get people
* started. For full guide, you can use {@link #getInfoLink()} to direct users.</li>
* </ul>
*
* @return A collection of command usage examples.
*/
@Nullable
Collection<String> getExampleUsages();
/**
* <p>Gets a link with more information on your generator plugin. Returning null means you do not wish to link
* users to any website related to your generator plugin.</p>
*
* <p>An example info: 'Click on https://www.amazinggenerator.io ;)'</p>
*
* <p>Some suggested places you can link to are: spigot resource page, github repo or your own plugin site.</p>
*
* @return Link to more info on your generator plugin.
*/
@Nullable
String getInfoLink();
/**
* Gets the java plugin for this generator. In short, return your own generator plugin instance.
*
* @return The associated plugin for this generator.
*/
@NotNull
Plugin getPlugin();
}
@@ -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.
@@ -0,0 +1,134 @@
package com.onarandombox.MultiverseCore.api;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Map;
/**
* API for handling generator plugins installed on the user's server.
*/
public interface MVGeneratorManager {
/**
* Register a generator plugin.
*
* @param generatorPlugin The {@link GeneratorPlugin} to register.
* @return True if successfully registered, else false.
*/
boolean register(@NotNull GeneratorPlugin generatorPlugin);
/**
* Check if a given generator string is valid.
*
* @param genString The generator string to check on.
* @param worldName The target world name to generate on.
* @return True if valid, else false.
*/
boolean isValidGenerator(@NotNull String genString, @NotNull String worldName);
/**
* Check if a given generator string is valid with reason of failure with {@link TestResult}.
*
* @param genString The generator string to check on.
* @param worldName The target world name to generate on.
* @return Result of the validation.
*/
@NotNull
TestResult validateGenerator(@NotNull String genString, @NotNull String worldName);
/**
* Checks if a plugin is a registered generator plugin.
*
* @param genPlugin The plugin to check on.
* @return True if is valid, else false.
*/
boolean isGeneratorPlugin(@NotNull Plugin genPlugin);
/**
* Checks if a plugin is a registered generator plugin.
*
* @param pluginName The plugin name to check on.
* @return True if is valid, else false.
*/
boolean isGeneratorPlugin(@NotNull String pluginName);
/**
* Gets the {@link GeneratorPlugin} for a given plugin if present.
*
* @param genPlugin The plugin that is associated to a {@link GeneratorPlugin}.
* @return The {@link GeneratorPlugin} if present, else null.
*/
@Nullable
GeneratorPlugin getGeneratorPlugin(@NotNull Plugin genPlugin);
/**
* Gets the {@link GeneratorPlugin} for a given plugin if present.
*
* @param pluginName The plugin name that is associated to a {@link GeneratorPlugin}.
* @return The {@link GeneratorPlugin} if present, else null.
*/
@Nullable
GeneratorPlugin getGeneratorPlugin(@NotNull String pluginName);
/**
* Gets all registered {@link GeneratorPlugin}.
*
* @return A collection of registered generator plugins.
*/
@NotNull
Collection<GeneratorPlugin> getGeneratorPlugins();
/**
* Gets all registered plugin names associate with {@link GeneratorPlugin}.
*
* @return A collection of registered generator plugin names.
*/
@NotNull
Collection<String> getGeneratorPluginNames();
/**
* Gets the default world generator string defined in 'bukkit.yml' for a given world.
*
* @param worldName The world to get default generator of.
* @return The generator string if present, else null.
*/
@Nullable
String getDefaultWorldGen(String worldName);
/**
* Gets all the world generator strings defined in 'bukkit.yml'.
*
* @return Map if world names and its respective default world generator strings.
*/
@NotNull
Map<String, String> getDefaultWorldGens();
/**
* Results from validating a generator.
*/
enum TestResult {
/**
* Successfully got {@link ChunkGenerator} from the world generator plugin.
*/
VALID,
/**
* Exceptions thrown while trying to get {@link ChunkGenerator} from the world generator plugin.
*/
ERRORS,
/**
* Plugin is present on the server, but doesnt look like a world generator.
*/
INVALID_GENERATOR,
/**
* Plugin not installed on the server.
*/
PLUGIN_DOES_NOT_EXIST
}
}
@@ -7,6 +7,7 @@
package com.onarandombox.MultiverseCore.api;
import com.onarandombox.MultiverseCore.generators.GeneratorManager;
import com.onarandombox.MultiverseCore.utils.PurgeWorlds;
import com.onarandombox.MultiverseCore.utils.SimpleWorldPurger;
import org.bukkit.World;
@@ -154,7 +155,9 @@ public interface MVWorldManager {
* @param generatorID The generator id.
* @param worldName The worldName to use as the default.
* @return A {@link ChunkGenerator} or null
* @deprecated Use {@link MVGeneratorManager#validateGenerator(String, String)}
*/
@Deprecated
ChunkGenerator getChunkGenerator(String generator, String generatorID, String worldName);
/**
@@ -249,7 +252,9 @@ public interface MVWorldManager {
/**
* This method populates an internal list and needs to be called after multiverse initialization.
* @deprecated This is now done by {@link GeneratorManager}.
*/
@Deprecated
void getDefaultWorldGenerators();
/**
@@ -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.
@@ -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?");
@@ -9,6 +9,7 @@ package com.onarandombox.MultiverseCore.commands;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MVGeneratorManager;
import com.pneumaticraft.commandhandler.CommandHandler;
import org.bukkit.ChatColor;
import org.bukkit.World.Environment;
@@ -18,8 +19,6 @@ import org.bukkit.command.CommandSender;
import org.bukkit.permissions.PermissionDefault;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@@ -98,14 +97,26 @@ public class CreateCommand extends MultiverseCommand {
}
// Determine if the generator is valid. #918
if (generator != null) {
List<String> genarray = new ArrayList<String>(Arrays.asList(generator.split(":")));
if (genarray.size() < 2) {
// If there was only one arg specified, pad with another empty one.
genarray.add("");
}
if (this.worldManager.getChunkGenerator(genarray.get(0), genarray.get(1), "test") == null) {
MVGeneratorManager.TestResult result = this.plugin.getMVGeneratorManager().validateGenerator(generator, worldName);
if (result != MVGeneratorManager.TestResult.VALID) {
// We have an invalid generator.
sender.sendMessage("Invalid generator! '" + generator + "'. " + ChatColor.RED + "Aborting world creation.");
switch (result) {
case ERRORS:
sender.sendMessage("An issue occurred while validating generator string '" + generator +
"'! This may indicate an issue with your generator plugin or an invalid generator id. Check console for errors!");
break;
case INVALID_GENERATOR:
sender.sendMessage("Invalid generator string '" + generator +
"'! The generator id you use is probably not supported by your generator plugin.");
break;
case PLUGIN_DOES_NOT_EXIST:
sender.sendMessage("That generator plugin is not installed on your server!");
break;
default:
sender.sendMessage("Invalid generator string '" + generator + "'!");
break;
}
sender.sendMessage(ChatColor.RED + "Aborting world creation...");
return;
}
}
@@ -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");
}
}
}
@@ -9,12 +9,19 @@ package com.onarandombox.MultiverseCore.commands;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.GeneratorPlugin;
import com.onarandombox.MultiverseCore.generators.SimpleGeneratorPlugin;
import net.milkbowl.vault.chat.Chat;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.Plugin;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
@@ -25,36 +32,70 @@ public class GeneratorCommand extends MultiverseCommand {
public GeneratorCommand(MultiverseCore plugin) {
super(plugin);
this.setName("World Information");
this.setCommandUsage("/mv generators");
this.setArgRange(0, 0);
this.setCommandUsage("/mv generators [plugin]");
this.setArgRange(0, 1);
this.addKey("mv generators");
this.addKey("mvgenerators");
this.addKey("mv gens");
this.addKey("mvgens");
this.addCommandExample("/mv generators");
this.setPermission("multiverse.core.generator", "Returns a list of Loaded Generator Plugins.", PermissionDefault.OP);
this.addCommandExample("/mv generators VoidGenerator");
this.setPermission("multiverse.core.generator", "Returns info of Loaded Generator Plugins.", PermissionDefault.OP);
}
@Override
public void runCommand(CommandSender sender, List<String> args) {
Logging.info("PLEASE IGNORE the 'Plugin X does not contain any generators' message below!");
Plugin[] plugins = this.plugin.getServer().getPluginManager().getPlugins();
List<String> generators = new ArrayList<String>();
for (Plugin p : plugins) {
if (p.isEnabled() && p.getDefaultWorldGenerator("world", "") != null) {
generators.add(p.getDescription().getName());
}
if (args.size() == 0) {
listKnownGenerators(sender);
return;
}
showGeneratorDetails(sender, args.get(0));
}
private void listKnownGenerators(CommandSender sender) {
sender.sendMessage(ChatColor.AQUA + "--- Loaded Generator Plugins ---");
String loadedGens = "";
StringBuilder loadedGens = new StringBuilder();
boolean altColor = false;
for (String s : generators) {
loadedGens += (altColor ? ChatColor.YELLOW : ChatColor.WHITE) + s + " ";
for (String s : this.plugin.getMVGeneratorManager().getGeneratorPluginNames()) {
loadedGens.append(altColor ? ChatColor.YELLOW : ChatColor.WHITE).append(s).append(' ');
altColor = !altColor;
}
if (loadedGens.length() == 0) {
loadedGens = ChatColor.RED + "No Generator Plugins found.";
loadedGens.append(ChatColor.RED).append("No Generator Plugins found.");
}
sender.sendMessage(loadedGens.toString());
}
private void showGeneratorDetails(CommandSender sender, String pluginName) {
Plugin genPlugin = Bukkit.getPluginManager().getPlugin(pluginName);
if (genPlugin == null) {
sender.sendMessage(ChatColor.RED + "You do not have a plugin named '"+ pluginName + "' on your server.");
return;
}
GeneratorPlugin generatorPlugin = this.plugin.getMVGeneratorManager().getGeneratorPlugin(genPlugin);
if (generatorPlugin == null) {
sender.sendMessage(ChatColor.RED + "'" + pluginName + "' does not look like a generator plugin.");
return;
}
sender.sendMessage(ChatColor.AQUA + "--- Info on " + generatorPlugin.getPlugin().getName() + " ---");
boolean hasAddInfo = false;
Collection<String> exampleUsages = generatorPlugin.getExampleUsages();
if (exampleUsages != null && exampleUsages.size() > 0) {
hasAddInfo = true;
sender.sendMessage("Usages:");
exampleUsages.forEach(sender::sendMessage);
}
String infoLink = generatorPlugin.getInfoLink();
if (infoLink != null) {
hasAddInfo = true;
sender.sendMessage("More Info: " + infoLink);
}
if (!hasAddInfo) {
sender.sendMessage(ChatColor.RED + "'" + pluginName + "' did not provide additional info to Multiverse.");
}
sender.sendMessage(loadedGens);
}
}
@@ -10,6 +10,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;
@@ -45,28 +46,6 @@ 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) {
@@ -84,7 +63,7 @@ public class ImportCommand extends MultiverseCommand {
}
ChatColor currColor = ChatColor.WHITE;
for (File file : files) {
if (file.isDirectory() && checkIfIsWorld(file) && !worldStrings.contains(file.getName())) {
if (file.isDirectory() && WorldNameChecker.isValidWorldFolder(file) && !worldStrings.contains(file.getName())) {
worldList += currColor + file.getName() + " ";
if (currColor == ChatColor.WHITE) {
currColor = ChatColor.YELLOW;
@@ -152,7 +131,7 @@ public class ImportCommand extends MultiverseCommand {
String worldList = this.getPotentialWorlds();
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));
@@ -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.
@@ -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);
@@ -26,12 +26,7 @@ import org.bukkit.entity.Player;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -55,58 +50,59 @@ public class VersionCommand extends MultiverseCommand {
}
private String getLegacyString() {
return "[Multiverse-Core] Multiverse-Core Version: " + this.plugin.getDescription().getVersion() + System.lineSeparator()
+ "[Multiverse-Core] Bukkit Version: " + this.plugin.getServer().getVersion() + System.lineSeparator()
+ "[Multiverse-Core] Loaded Worlds: " + this.plugin.getMVWorldManager().getMVWorlds() + System.lineSeparator()
+ "[Multiverse-Core] Multiverse Plugins Loaded: " + this.plugin.getPluginCount() + System.lineSeparator()
+"[Multiverse-Core] Economy being used: " + plugin.getEconomist().getEconomyName() + System.lineSeparator()
+ "[Multiverse-Core] Permissions Plugin: " + this.plugin.getMVPerms().getType() + System.lineSeparator()
+ "[Multiverse-Core] Dumping Config Values: (version " + this.plugin.getMVConfig().getVersion() + ")" + System.lineSeparator()
+ "[Multiverse-Core] enforceaccess: " + plugin.getMVConfig().getEnforceAccess() + System.lineSeparator()
+ "[Multiverse-Core] prefixchat: " + plugin.getMVConfig().getPrefixChat() + System.lineSeparator()
+ "[Multiverse-Core] prefixchatformat: " + plugin.getMVConfig().getPrefixChatFormat() + System.lineSeparator()
+ "[Multiverse-Core] useasyncchat: " + plugin.getMVConfig().getUseAsyncChat() + System.lineSeparator()
+ "[Multiverse-Core] teleportintercept: " + plugin.getMVConfig().getTeleportIntercept() + System.lineSeparator()
+ "[Multiverse-Core] firstspawnoverride: " + plugin.getMVConfig().getFirstSpawnOverride() + System.lineSeparator()
+ "[Multiverse-Core] displaypermerrors: " + plugin.getMVConfig().getDisplayPermErrors() + System.lineSeparator()
+ "[Multiverse-Core] globaldebug: " + plugin.getMVConfig().getGlobalDebug() + System.lineSeparator()
+ "[Multiverse-Core] silentstart: " + plugin.getMVConfig().getSilentStart() + System.lineSeparator()
+ "[Multiverse-Core] messagecooldown: " + plugin.getMessaging().getCooldown() + System.lineSeparator()
+ "[Multiverse-Core] version: " + plugin.getMVConfig().getVersion() + System.lineSeparator()
+ "[Multiverse-Core] firstspawnworld: " + plugin.getMVConfig().getFirstSpawnWorld() + System.lineSeparator()
+ "[Multiverse-Core] teleportcooldown: " + plugin.getMVConfig().getTeleportCooldown() + System.lineSeparator()
+ "[Multiverse-Core] defaultportalsearch: " + plugin.getMVConfig().isUsingDefaultPortalSearch() + System.lineSeparator()
+ "[Multiverse-Core] portalsearchradius: " + plugin.getMVConfig().getPortalSearchRadius() + System.lineSeparator()
+ "[Multiverse-Core] autopurge: " + plugin.getMVConfig().isAutoPurgeEnabled() + System.lineSeparator()
+ "[Multiverse-Core] Special Code: FRN002" + System.lineSeparator();
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() {
return "# Multiverse-Core" + System.lineSeparator()
+ "## Overview" + System.lineSeparator()
+ "| Name | Value |" + System.lineSeparator()
+ "| --- | --- |" + System.lineSeparator()
+ "| Multiverse-Core Version | `" + this.plugin.getDescription().getVersion() + "` |" + System.lineSeparator()
+ "| Bukkit Version | `" + this.plugin.getServer().getVersion() + "` |" + System.lineSeparator()
+ "| Loaded Worlds | `" + this.plugin.getMVWorldManager().getMVWorlds() + "` |" + System.lineSeparator()
+ "| Multiverse Plugins Loaded | `" + this.plugin.getPluginCount() + "` |" + System.lineSeparator()
+ "| Economy being used | `" + plugin.getEconomist().getEconomyName() + "` |" + System.lineSeparator()
+ "| Permissions Plugin | `" + this.plugin.getMVPerms().getType() + "` |" + System.lineSeparator()
+ "## Parsed Config" + System.lineSeparator()
+ "These are what Multiverse thought the in-memory values of the config were." + System.lineSeparator() + System.lineSeparator()
+ "| Config Key | Value |" + System.lineSeparator()
+ "| --- | --- |" + System.lineSeparator()
+ "| version | `" + this.plugin.getMVConfig().getVersion() + "` |" + System.lineSeparator()
+ "| messagecooldown | `" + plugin.getMessaging().getCooldown() + "` |" + System.lineSeparator()
+ "| teleportcooldown | `" + plugin.getMVConfig().getTeleportCooldown() + "` |" + System.lineSeparator()
+ "| worldnameprefix | `" + plugin.getMVConfig().getPrefixChat() + "` |" + System.lineSeparator()
+ "| worldnameprefixFormat | `" + plugin.getMVConfig().getPrefixChatFormat() + "` |" + System.lineSeparator()
+ "| enforceaccess | `" + plugin.getMVConfig().getEnforceAccess() + "` |" + System.lineSeparator()
+ "| displaypermerrors | `" + plugin.getMVConfig().getDisplayPermErrors() + "` |" + System.lineSeparator()
+ "| teleportintercept | `" + plugin.getMVConfig().getTeleportIntercept() + "` |" + System.lineSeparator()
+ "| firstspawnoverride | `" + plugin.getMVConfig().getFirstSpawnOverride() + "` |" + System.lineSeparator()
+ "| firstspawnworld | `" + plugin.getMVConfig().getFirstSpawnWorld() + "` |" + System.lineSeparator()
+ "| debug | `" + plugin.getMVConfig().getGlobalDebug() + "` |" + System.lineSeparator();
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 void addVersionInfoToEvent(MVVersionEvent event) {
@@ -114,15 +110,16 @@ public class VersionCommand extends MultiverseCommand {
event.appendVersionInfo(this.getLegacyString());
// add the legacy file, but as markdown so it's readable
event.putDetailedVersionInfo("version.md", this.getMarkdownString());
// TODO Readd this in 5.0.0
// event.putDetailedVersionInfo("version.md", this.getMarkdownString());
// add config.yml
File configFile = new File(this.plugin.getDataFolder(), "config.yml");
event.putDetailedVersionInfo("version.md", configFile);
event.putDetailedVersionInfo("multiverse-core/config.yml", configFile);
// add worlds.yml
File worldsFile = new File(this.plugin.getDataFolder(), "worlds.yml");
event.putDetailedVersionInfo("version.md", worldsFile);
event.putDetailedVersionInfo("multiverse-core/worlds.yml", worldsFile);
}
@Override
@@ -138,18 +135,20 @@ public class VersionCommand extends MultiverseCommand {
this.plugin.getServer().getPluginManager().callEvent(versionEvent);
if (CommandHandler.hasFlag("--include-plugin-list", args)) {
versionEvent.appendVersionInfo(System.lineSeparator() + "Plugins: " + getPluginList());
versionEvent.appendVersionInfo('\n' + "Plugins: " + getPluginList());
versionEvent.putDetailedVersionInfo("plugins.txt", "Plugins: " + getPluginList());
}
final String versionInfo = versionEvent.getVersionInfo();
versionEvent.putDetailedVersionInfo("version.txt", versionInfo);
final Map<String, String> files = versionEvent.getDetailedVersionInfo();
// log to console
String[] lines = versionInfo.split(System.lineSeparator());
String[] lines = versionInfo.split("\\r?\\n");
for (String line : lines) {
if (!line.isEmpty()) {
Logging.info(line);
this.plugin.getServer().getLogger().info(line);
}
}
@@ -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,26 @@ 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.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 +46,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.
@@ -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
}
@@ -0,0 +1,311 @@
package com.onarandombox.MultiverseCore.generators;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.GeneratorPlugin;
import com.onarandombox.MultiverseCore.api.MVGeneratorManager;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
/**
* Default implementation of {@link MVGeneratorManager} to facilitate the detection and management of generator
* plugins installed on user's server.
*/
public class GeneratorManager implements MVGeneratorManager {
private final MultiverseCore plugin;
private final Map<String, String> defaultGens;
private Map<String, GeneratorPlugin> generatorPluginMap;
public GeneratorManager(MultiverseCore plugin) {
this.plugin = plugin;
this.defaultGens = new HashMap<>();
loadDefaultWorldGenerators();
findAndRegisterAllGeneratorPlugins();
Bukkit.getPluginManager().registerEvents(new GeneratorListener(), this.plugin);
}
/**
* Loads default generator strings defined in 'bukkit.yml'.
*/
private void loadDefaultWorldGenerators() {
this.generatorPluginMap = new HashMap<>();
File[] files = this.plugin.getServerFolder().listFiles((file, s) -> s.equalsIgnoreCase("bukkit.yml"));
if (files == null || files.length != 1) {
Logging.fine("Could not read 'bukkit.yml'. Any Default worldgenerators will not be loaded!");
return;
}
FileConfiguration bukkitConfig = YamlConfiguration.loadConfiguration(files[0]);
if (!bukkitConfig.isConfigurationSection("worlds")) {
Logging.fine("'bukkit.yml' missing worlds config section. No default generators found!");
return;
}
Set<String> keys = bukkitConfig.getConfigurationSection("worlds").getKeys(false);
for (String key : keys) {
this.defaultGens.put(key, bukkitConfig.getString("worlds." + key + ".generator", ""));
}
this.generatorPluginMap = Collections.unmodifiableMap(this.generatorPluginMap);
}
/**
* Register all generator plugins detected.
*/
private void findAndRegisterAllGeneratorPlugins() {
Arrays.stream(Bukkit.getPluginManager().getPlugins()).forEach(this::register);
}
/**
* Attempts to register a plugin as {@link SimpleGeneratorPlugin}.
*
* @param genPlugin The plugin to register.
* @return True if registered successfully, else false.
*/
private boolean register(@NotNull Plugin genPlugin) {
return this.register(genPlugin, SimpleGeneratorPlugin.DEFAULT_TEST_ID);
}
/**
* Attempts to register a plugin as {@link SimpleGeneratorPlugin}.
*
* @param genPlugin The plugin to register.
* @param id Generator Id to test for valid chunk generator.
* @return True if registered successfully, else false.
*/
private boolean register(@NotNull Plugin genPlugin, String id) {
Logging.finer("Attempting to register %s as a generator...", genPlugin.getName());
if (this.isGeneratorPlugin(genPlugin)) {
return false;
}
if (!simpleTestGen(genPlugin, id)) {
Logging.finer("%s is probably not a generator plugin!", genPlugin.getName());
return false;
}
this.generatorPluginMap.put(genPlugin.getName(), new SimpleGeneratorPlugin(genPlugin));
Logging.finer("Registered %s as a simple generator plugin.", genPlugin.getName());
return true;
}
/**
* Basic test to see if plugin is a valid generator.
*
* @param generator The potential generator plugin.
* @param id Generator Id to test for valid chunk generator.
* @return True if plugin is a valid generator, else false.
*/
private boolean simpleTestGen(@Nullable Plugin generator, String id) {
if (generator == null) {
return false;
}
// Since we are unsure if the plugin is even suppose to be a generator, we assume any error means its
// not a generator plugin.
try {
return generator.getDefaultWorldGenerator(SimpleGeneratorPlugin.TEST_WORLDNAME, id) != null;
} catch (Exception ignore) {
return false;
}
}
/**
* Unregisters a plugin.
*
* @param genPlugin The plugin to unregister.
* @return True if the plugin was present and now unregistered, else false.
*/
private boolean unregister(@NotNull Plugin genPlugin) {
return this.generatorPluginMap.remove(genPlugin.getName()) != null;
}
/**
* {@inheritDoc}
*/
@Override
public boolean register(@NotNull GeneratorPlugin generatorPlugin) {
Plugin genPlugin = generatorPlugin.getPlugin();
// Make sure not registered before.
GeneratorPlugin registeredGeneratorPlugin = this.getGeneratorPlugin(genPlugin);
if (registeredGeneratorPlugin != null) {
if (!(registeredGeneratorPlugin instanceof SimpleGeneratorPlugin)) {
throw new IllegalStateException("You cannot register plugin for '" + genPlugin.getName() + "' twice!");
}
// If it's auto registration by MV, we can remove in favour of the custom one.
this.unregister(genPlugin);
}
if (this.safelyTestGenerator(genPlugin, generatorPlugin::getDefaultChunkGenerator) != TestResult.VALID) {
return false;
}
this.generatorPluginMap.put(genPlugin.getName(), generatorPlugin);
Logging.fine("Registered %s as a simple generator plugin.", genPlugin.getName());
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isValidGenerator(@NotNull String genString, @NotNull String worldName) {
return validateGenerator(genString, worldName) == TestResult.VALID;
}
/**
* {@inheritDoc}
*/
@Override
@NotNull
public TestResult validateGenerator(@NotNull String genString, @NotNull String worldName) {
String[] genArray = genString.split(":", 2);
String pluginName = genArray[0];
String id = (genArray.length == 1) ? "" : genArray[1];
Plugin genPlugin = Bukkit.getPluginManager().getPlugin(pluginName);
if (genPlugin == null) {
return TestResult.PLUGIN_DOES_NOT_EXIST;
}
if (!this.isGeneratorPlugin(genPlugin)) {
// Tries to register again with specific Id defined.
if (!this.register(genPlugin, id)) {
return TestResult.INVALID_GENERATOR;
}
}
GeneratorPlugin generatorPlugin = this.getGeneratorPlugin(genPlugin);
if (generatorPlugin == null) {
return TestResult.INVALID_GENERATOR;
}
TestResult testResult = safelyTestGenerator(generatorPlugin.getPlugin(), () -> generatorPlugin.getChunkGenerator(id, worldName));
if (testResult == TestResult.VALID && generatorPlugin instanceof SimpleGeneratorPlugin) {
((SimpleGeneratorPlugin) generatorPlugin).addKnownWorkingId(id);
}
return testResult;
}
/**
* Tries to get chunk generator with wrapper to catch any exceptions that may occur.
*
* @param genPlugin The generator plugin.
* @param genGetter Logic to get the chunk generator.
* @return VALID if successfully got a not-null chunk generator, INVALID_GENERATOR if null,
* ERRORS if exception is thrown.
*/
@NotNull
private TestResult safelyTestGenerator(Plugin genPlugin, Callable<ChunkGenerator> genGetter) {
TestResult result = this.plugin.getUnsafeCallWrapper().wrap(
() -> genGetter.call() == null ? TestResult.INVALID_GENERATOR : TestResult.VALID,
genPlugin.getName(),
"Failed to get the chunk generator: %s"
);
return (result == null) ? TestResult.ERRORS : result;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isGeneratorPlugin(@NotNull Plugin genPlugin) {
return this.isGeneratorPlugin(genPlugin.getName());
}
/**
* {@inheritDoc}
*/
@Override
public boolean isGeneratorPlugin(@NotNull String pluginName) {
return this.generatorPluginMap.containsKey(pluginName);
}
/**
* {@inheritDoc}
*/
@Override
@Nullable
public GeneratorPlugin getGeneratorPlugin(@NotNull Plugin genPlugin) {
return this.getGeneratorPlugin(genPlugin.getName());
}
/**
* {@inheritDoc}
*/
@Override
@Nullable
public GeneratorPlugin getGeneratorPlugin(@NotNull String pluginName) {
return this.generatorPluginMap.get(pluginName);
}
/**
* {@inheritDoc}
*/
@Override
@NotNull
public Collection<GeneratorPlugin> getGeneratorPlugins() {
return this.generatorPluginMap.values();
}
/**
* {@inheritDoc}
*/
@Override
@NotNull
public Collection<String> getGeneratorPluginNames() {
return this.generatorPluginMap.keySet();
}
/**
* {@inheritDoc}
*/
@Override
@Nullable
public String getDefaultWorldGen(String worldName) {
return this.defaultGens.get(worldName);
}
/**
* {@inheritDoc}
*/
@Override
@NotNull
public Map<String, String> getDefaultWorldGens() {
return this.defaultGens;
}
/**
* Listen to when a plugin enables/disable to register and unregister accordingly.
*/
private class GeneratorListener implements Listener {
@EventHandler
public void onEnable(PluginEnableEvent event) {
register(event.getPlugin());
}
@EventHandler
public void onDisable(PluginDisableEvent event) {
unregister(event.getPlugin());
}
}
}
@@ -0,0 +1,94 @@
package com.onarandombox.MultiverseCore.generators;
import com.onarandombox.MultiverseCore.api.GeneratorPlugin;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* A default implementation of {@link GeneratorPlugin} for those generator plugins that do not provide their own
* custom {@link GeneratorPlugin} implementation to Multiverse.
*/
public class SimpleGeneratorPlugin implements GeneratorPlugin {
public static String TEST_WORLDNAME = "test";
public static String DEFAULT_TEST_ID = "";
private final Plugin plugin;
private final List<String> workingIds;
SimpleGeneratorPlugin(Plugin plugin) {
this(plugin, DEFAULT_TEST_ID);
}
SimpleGeneratorPlugin(Plugin plugin, String testedId) {
this.plugin = plugin;
this.workingIds = new ArrayList<>();
this.workingIds.add(testedId);
}
/**
* Adds a known generator id that was tested to be working.
*
* @param id The known working generator id.
*/
void addKnownWorkingId(String id) {
if (!this.workingIds.contains(id)) {
this.workingIds.add(id);
}
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull Collection<String> suggestIds(@Nullable String currentIdInput) {
return this.workingIds;
}
/**
* {@inheritDoc}
*/
@Override
public @Nullable ChunkGenerator getDefaultChunkGenerator() throws Exception {
return this.plugin.getDefaultWorldGenerator(TEST_WORLDNAME, this.workingIds.get(0));
}
/**
* {@inheritDoc}
*/
@Override
public @Nullable ChunkGenerator getChunkGenerator(String id, String worldName) throws Exception {
return this.plugin.getDefaultWorldGenerator(worldName, id);
}
/**
* {@inheritDoc}
*/
@Override
public @Nullable Collection<String> getExampleUsages() {
return null;
}
/**
* {@inheritDoc}
* @return
*/
@Override
public @Nullable String getInfoLink() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull Plugin getPlugin() {
return this.plugin;
}
}
@@ -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;
}
}
@@ -72,12 +72,11 @@ 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 true if it had success
*/
public static boolean copyFolder(File source, File target, Logger log) {
return copyFolder(source, target, null, log);
public static boolean copyFolder(File source, File target) {
return copyFolder(source, target, null);
}
/**
@@ -85,11 +84,10 @@ public class FileUtils {
* @param source Source-File
* @param target Target-File
* @param excludeFiles files to ignore and not copy over to Target-File
* @param log A logger that logs the operation
*
* @return true if it had success
*/
public static boolean copyFolder(File source, File target, List<String> excludeFiles, Logger log) {
public static boolean copyFolder(File source, File target, List<String> excludeFiles) {
Path sourceDir = source.toPath();
Path targetDir = target.toPath();
@@ -97,7 +95,7 @@ public class FileUtils {
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;
}
}
@@ -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}-[34][0-9a-fA-F]{3}-[89ab][0-9a-fA-F]{3}-[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;
}
}
}
@@ -40,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
@@ -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;
}
}
@@ -74,6 +74,7 @@ public class WorldManager implements MVWorldManager {
* {@inheritDoc}
*/
@Override
@Deprecated
public void getDefaultWorldGenerators() {
this.defaultGens = new HashMap<String, String>();
File[] files = this.plugin.getServerFolder().listFiles(new FilenameFilter() {
@@ -91,7 +92,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!");
}
}
@@ -130,7 +131,7 @@ public class WorldManager implements MVWorldManager {
}
// Check for valid world name
if (!(isValidWorldName(oldName) && isValidWorldName(newName))) {
if (!(WorldNameChecker.isValidWorldName(oldName) && WorldNameChecker.isValidWorldName(oldName))) {
return false;
}
@@ -140,7 +141,7 @@ public class WorldManager implements MVWorldManager {
// 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;
}
@@ -162,14 +163,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);
@@ -187,7 +182,7 @@ public class WorldManager implements MVWorldManager {
oldWorld.getCBWorld().save();
}
Logging.config("Copying files for world '%s'", oldName);
if (!FileUtils.copyFolder(oldWorldFile, newWorldFile, ignoreFiles, Logging.getLogger())) {
if (!FileUtils.copyFolder(oldWorldFile, newWorldFile, ignoreFiles)) {
Logging.warning("Failed to copy files for world '%s', see the log info", newName);
return false;
}
@@ -208,16 +203,16 @@ public class WorldManager implements MVWorldManager {
// save the worlds config to disk (worlds.yml)
if (!saveWorldsConfig()) {
this.plugin.log(Level.SEVERE, "Failed to save worlds.yml");
Logging.severe("Failed to save worlds.yml");
return false;
}
// actually load the world
if (doLoad(newName)) {
this.plugin.log(Level.FINE, "Succeeded at loading cloned world '" + newName + "'");
Logging.fine("Succeeded at loading cloned world '" + newName + "'");
return true;
}
this.plugin.log(Level.SEVERE, "Failed to load the cloned world '" + newName + "'");
Logging.severe("Failed to load the cloned world '" + newName + "'");
return false;
}
@@ -244,7 +239,9 @@ public class WorldManager implements MVWorldManager {
return false;
}
if (!isValidWorldName(name)) {
if (!WorldNameChecker.isValidWorldName(name)) {
Logging.warning("Invalid world name '" + name + "'");
Logging.warning("World name should not contain spaces or special characters!");
return false;
}
@@ -290,7 +287,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;
}
@@ -305,6 +302,7 @@ public class WorldManager implements MVWorldManager {
* {@inheritDoc}
*/
@Override
@Deprecated
public ChunkGenerator getChunkGenerator(String generator, final String generatorID, final String worldName) {
if (generator == null) {
return null;
@@ -363,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) {
@@ -430,31 +428,16 @@ public class WorldManager implements MVWorldManager {
}
}
/**
* Check if the world name is allowed
*
* @param name Name of the world
* @return True if the world world name is valid based on regex
*/
private boolean isValidWorldName(String name) {
if (!worldNamePattern.matcher(name).matches()) {
Logging.warning("Invalid world name '" + name + "'");
Logging.warning("World name should not contain spaces or special characters!");
return false;
}
return true;
}
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) {
@@ -494,8 +477,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;
}
@@ -525,6 +508,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
@@ -535,7 +525,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;
}
@@ -551,7 +541,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;
@@ -706,10 +696,7 @@ public class WorldManager implements MVWorldManager {
for (World w : myWorlds) {
String name = w.getName();
if (!worldsFromTheConfig.containsKey(name)) {
String generator = null;
if (this.defaultGens.containsKey(name)) {
generator = this.defaultGens.get(name);
}
String generator = this.plugin.getMVGeneratorManager().getDefaultWorldGen(name);
this.addWorld(name, w.getEnvironment(), String.valueOf(w.getSeed()), w.getWorldType(), w.canGenerateStructures(), generator);
}
}
@@ -865,7 +852,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;
}
}
@@ -937,6 +924,9 @@ public class WorldManager implements MVWorldManager {
return this.configWorlds;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasUnloadedWorld(String name, boolean includeLoaded) {
if (getMVWorld(name) != null) {
@@ -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
}
}
@@ -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());
@@ -207,7 +207,7 @@ public class TestWorldStuff {
assertEquals(0, creator.getCore().getMVWorldManager().getMVWorlds().size());
// Verify
verify(mockCommandSender).sendMessage("Invalid generator! 'BogusGen'. " + ChatColor.RED + "Aborting world creation.");
verify(mockCommandSender).sendMessage("That generator plugin is not installed on your server!");
}
@Test
@@ -81,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));
@@ -107,7 +107,7 @@ public class FileUtilsTest {
assertFalse(Files.isRegularFile(targetChildDirFile));
assertFalse(Files.isRegularFile(targetChildIgnoreFile));
assertTrue(FileUtils.copyFolder(parentDir.toFile(), targetDir.toFile(), excludeFiles, Logging.getLogger()));
assertTrue(FileUtils.copyFolder(parentDir.toFile(), targetDir.toFile(), excludeFiles));
assertTrue(Files.isDirectory(targetDir));
assertTrue(Files.isRegularFile(targetFile));
@@ -129,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));
@@ -145,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));