Compare commits

..
9 Commits
Author SHA1 Message Date
Ben Wooandmontlikadani 3e85e42bd0 Update src/main/java/com/onarandombox/MultiverseCore/utils/WorldManager.java
Co-authored-by: montlikadani <montlikada@gmail.com>
2021-02-18 23:20:13 +08:00
benwoo1110 3f2ec3d40f Refactor clone operation with CloneHelper class. 2020-12-12 10:23:44 +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
7 changed files with 211 additions and 119 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: '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: '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: '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.
+1 -1
View File
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.onarandombox.multiversecore</groupId>
<artifactId>Multiverse-Core</artifactId>
<version>4.2.2</version>
<version>4.2.3-SNAPSHOT</version>
<name>Multiverse-Core</name>
<description>World Management Plugin</description>
<properties>
@@ -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);
}
}
@@ -47,7 +47,6 @@ import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
@@ -63,6 +62,8 @@ public class WorldManager implements MVWorldManager {
private Map<String, String> defaultGens;
private String firstSpawn;
private static final List<String> CLONE_IGNORE_FILES = Arrays.asList("session.lock", "uid.dat");
public WorldManager(MultiverseCore core) {
this.plugin = core;
this.worldsFromTheConfig = new HashMap<String, WorldProperties>();
@@ -95,6 +96,190 @@ public class WorldManager implements MVWorldManager {
}
}
/**
* Makes cloning easier to understand and manage.
*/
private class CloneHelper {
private String oldName;
private String newName;
private File oldWorldFile;
private File newWorldFile;
private MultiverseWorld oldWorld;
public CloneHelper(String oldName, String newName) {
this.oldName = oldName;
this.newName = newName;
}
/**
* The clone operation.
*
* @return True if clone is successful, false otherwise.
*/
public boolean run() {
if (!validCloneParameters()) {
Logging.warning("Invalid clone parameters");
return false;
}
initWorldFiles();
if (newWorldFile.exists()) {
Logging.warning("Folder for new world '%s' already exists", newName);
return false;
}
oldWorld = getMVWorld(oldName);
if (!isOldWorldLoadable()) {
Logging.severe("Old world '%s' is not loadable", oldName);
return false;
}
boolean wasAutoSave = manuallySaveWorld();
if (!copyWorldFolder()) {
return false;
}
revertBackAutoSave(wasAutoSave);
return initNewCloneWorld();
}
/**
* Ensure that world with oldName can be clone to a world called newName.
*
* @return True if parameters are valid, otherwise false.
*/
private boolean validCloneParameters() {
String originalOldName = oldName;
if (!isWorldFromConfig(oldName)) {
oldName = getWorldByAliasFromConfig(oldName);
}
if (oldName == null) {
Logging.warning("Old world '%s' does not exist", originalOldName);
return false;
}
if (isWorldFromConfig(newName)) {
Logging.warning("New world '%s' already exists", newName);
return false;
}
if (!isValidWorldName(newName)) {
Logging.warning("New world name '%s' is invalid", newName);
return false;
}
return true;
}
/**
* Get world folders from world container.
*/
private void initWorldFiles() {
oldWorldFile = new File(plugin.getServer().getWorldContainer(), oldName);
newWorldFile = new File(plugin.getServer().getWorldContainer(), newName);
}
/**
* Ensure that old world can be loaded and saved properly.
*
* @return True if old world can be loaded successfully, false otherwise.
*/
private boolean isOldWorldLoadable() {
if (oldWorld != null) {
return true;
}
Logging.fine("Old world '%s' is currently unloaded. Attempting to load it...", oldName);
WorldProperties props = worldsFromTheConfig.get(oldName);
boolean wasLoadSpawn = worldsFromTheConfig.get(oldName).isKeepingSpawnInMemory();
if (wasLoadSpawn) {
props.setKeepSpawnInMemory(false);
}
if (!loadWorld(oldName)) {
Logging.severe("Failed to load the old world '%s'", oldName);
return false;
}
getMVWorld(oldName).getCBWorld().setAutoSave(false);
if (!unloadWorld(oldName, true)) {
Logging.severe("Failed to unload the old world '%S'", oldName);
return false;
}
if (wasLoadSpawn) {
props.setKeepSpawnInMemory(true);
}
return true;
}
/**
* Duplicating old world folder to the new world folder.
*
* @return True if copy process was successful, false otherwise.
*/
private boolean copyWorldFolder() {
Logging.fine("Copying files for world '%s'", oldName);
if (!FileUtils.copyFolder(oldWorldFile, newWorldFile, CLONE_IGNORE_FILES, Logging.getLogger()) || !newWorldFile.exists()) {
Logging.severe("Failed to copy files for world '%s', see the log info", newName);
return false;
}
Logging.fine("Succeeded at copying files");
return true;
}
/**
* Ensure world is save being copying world files.
*
* @return Previous auto-save setting for the old world.
*/
private boolean manuallySaveWorld() {
if (oldWorld != null && oldWorld.getCBWorld().isAutoSave()) {
Logging.config("Saving world '%s'", oldName);
oldWorld.getCBWorld().setAutoSave(false);
oldWorld.getCBWorld().save();
return true;
}
return false;
}
private void revertBackAutoSave(boolean wasAutoSave) {
if (oldWorld != null && wasAutoSave) {
Logging.fine("Revert back to enabling auto-save");
oldWorld.getCBWorld().setAutoSave(true);
}
}
/**
* Initialize new properties with old ones.
*/
private void copyPropertiesToNewWorld() {
WorldProperties newProps = new WorldProperties();
newProps.copyValues(worldsFromTheConfig.get(oldName));
newProps.setAlias(""); // don't keep the alias the same -- that would be useless
worldsFromTheConfig.put(newName, newProps);
}
/**
* Load up the newly copied clone world.
*/
private boolean initNewCloneWorld() {
copyPropertiesToNewWorld();
if (!saveWorldsConfig()) {
Logging.severe("Failed to save worlds.yml");
return false;
}
if (!doLoad(newName)) {
Logging.severe("Failed to load the cloned world '" + newName + "'");
return false;
}
Logging.fine("Succeeded at loading cloned world '" + newName + "'");
return true;
}
}
/**
* {@inheritDoc}
* @deprecated Use {@link #cloneWorld(String, String)} instead.
@@ -110,113 +295,7 @@ public class WorldManager implements MVWorldManager {
*/
@Override
public boolean cloneWorld(String oldName, String newName) {
// Make sure we already know about the old world and that we don't
// already know about the new world.
if (!this.worldsFromTheConfig.containsKey(oldName)) {
for (Map.Entry<String, WorldProperties> entry : this.worldsFromTheConfig.entrySet()) {
if (oldName.equals(entry.getValue().getAlias())) {
oldName = entry.getKey();
break;
}
}
if (!this.worldsFromTheConfig.containsKey(oldName)) {
Logging.warning("Old world '%s' does not exist", oldName);
return false;
}
}
if (this.isMVWorld(newName)) {
Logging.warning("New world '%s' already exists", newName);
return false;
}
// Check for valid world name
if (!(isValidWorldName(oldName) && isValidWorldName(newName))) {
return false;
}
final File oldWorldFile = new File(this.plugin.getServer().getWorldContainer(), oldName);
final File newWorldFile = new File(this.plugin.getServer().getWorldContainer(), newName);
final List<String> ignoreFiles = new ArrayList<>(Arrays.asList("session.lock", "uid.dat"));
// Make sure the new world doesn't exist outside of multiverse.
if (newWorldFile.exists()) {
Logging.warning("Folder for new world '%s' already exists", newName);
return false;
}
// Load the old world... but just the metadata.
boolean wasJustLoaded = false;
boolean wasLoadSpawn = false;
if (this.plugin.getServer().getWorld(oldName) == null) {
wasJustLoaded = true;
WorldProperties props = this.worldsFromTheConfig.get(oldName);
wasLoadSpawn = props.isKeepingSpawnInMemory();
if (wasLoadSpawn) {
// No chunks please.
props.setKeepSpawnInMemory(false);
}
if (!this.loadWorld(oldName)) {
return false;
}
this.plugin.getServer().getWorld(oldName).setAutoSave(false);
}
// Grab a bit of metadata from the old world.
MultiverseWorld oldWorld = getMVWorld(oldName);
// Don't need the loaded world anymore.
if (wasJustLoaded) {
this.unloadWorld(oldName, true);
oldWorld = null;
if (wasLoadSpawn) {
this.worldsFromTheConfig.get(oldName).setKeepSpawnInMemory(true);
}
}
boolean wasAutoSave = false;
if (oldWorld != null && oldWorld.getCBWorld().isAutoSave()) {
wasAutoSave = true;
Logging.config("Saving world '%s'", oldName);
oldWorld.getCBWorld().setAutoSave(false);
oldWorld.getCBWorld().save();
}
Logging.config("Copying files for world '%s'", oldName);
if (!FileUtils.copyFolder(oldWorldFile, newWorldFile, ignoreFiles, Logging.getLogger())) {
Logging.warning("Failed to copy files for world '%s', see the log info", newName);
return false;
}
if (oldWorld != null && wasAutoSave) {
oldWorld.getCBWorld().setAutoSave(true);
}
if (newWorldFile.exists()) {
Logging.fine("Succeeded at copying files");
// initialize new properties with old ones
WorldProperties newProps = new WorldProperties();
newProps.copyValues(this.worldsFromTheConfig.get(oldName));
// don't keep the alias the same -- that would be useless
newProps.setAlias("");
// store the new properties in worlds config map
this.worldsFromTheConfig.put(newName, newProps);
// save the worlds config to disk (worlds.yml)
if (!saveWorldsConfig()) {
this.plugin.log(Level.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 + "'");
return true;
}
this.plugin.log(Level.SEVERE, "Failed to load the cloned world '" + newName + "'");
return false;
}
Logging.warning("Failed to copy files for world '%s', see the log info", newName);
return false;
return new CloneHelper(oldName, newName).run();
}
/**
@@ -697,6 +776,19 @@ public class WorldManager implements MVWorldManager {
return false;
}
private boolean isWorldFromConfig(String name) {
return this.worldsFromTheConfig.containsKey(name);
}
private String getWorldByAliasFromConfig(String name) {
return this.worldsFromTheConfig.entrySet()
.stream()
.filter(worldEntry -> name.equals(worldEntry.getValue().getAlias()))
.map(Map.Entry::getKey)
.findFirst()
.orElse(null);
}
/**
* {@inheritDoc}
*/