mirror of
https://github.com/Multiverse/Multiverse-Core.git
synced 2025-03-13 07:10:02 +01:00
Update cloneWorld().
- Make it actually work. - Support for unloaded worlds - saves memory! - The Thread code seems unnecessary since the main thread just waits for it to finish, so I'm removing it. - Added cloneWorld(String, String). - Deprecate the old cloneWorld() method. Closes #1436 Closes #1491 Due to some limitations, I have to temporarily load the old world in order to properly clone. However, **no chunks are loaded during this process.**
This commit is contained in:
parent
762d8e3ebb
commit
528dc25fcb
6
pom.xml
6
pom.xml
@ -315,6 +315,12 @@
|
||||
<version>1.0.9</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>craftbukkit</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- End of Logging Dependency -->
|
||||
<!-- Start of Test Dependencies -->
|
||||
|
@ -374,7 +374,7 @@ public class WorldProperties extends SerializationConfig {
|
||||
this.flushPendingVPropChanges();
|
||||
}
|
||||
|
||||
String getAlias() {
|
||||
public String getAlias() {
|
||||
return this.alias;
|
||||
}
|
||||
|
||||
|
@ -64,16 +64,30 @@ public interface MVWorldManager {
|
||||
*
|
||||
* @param oldName Name of world to be copied
|
||||
* @param newName Name of world to be created
|
||||
* @param generator The Custom generator plugin to use.
|
||||
* @param generator The Custom generator plugin to use. Ignored.
|
||||
* @return True if the world is copied successfully, false if not.
|
||||
* @deprecated Use {@link #cloneWorld(String, String)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
boolean cloneWorld(String oldName, String newName, String generator);
|
||||
|
||||
/**
|
||||
* Remove the world from the Multiverse list, from the
|
||||
* config and deletes the folder.
|
||||
* Make a copy of a world.
|
||||
*
|
||||
* @param name The name of the world to remove
|
||||
* @param oldName
|
||||
* Name of world to be copied
|
||||
* @param newName
|
||||
* Name of world to be created
|
||||
* @return True if the world is copied successfully, false if not.
|
||||
*/
|
||||
boolean cloneWorld(String oldName, String newName);
|
||||
|
||||
/**
|
||||
* Remove the world from the Multiverse list, from the config and deletes
|
||||
* the folder.
|
||||
*
|
||||
* @param name
|
||||
* The name of the world to remove
|
||||
* @return True if success, false if failure.
|
||||
*/
|
||||
boolean deleteWorld(String name);
|
||||
@ -288,4 +302,16 @@ public interface MVWorldManager {
|
||||
boolean regenWorld(String name, boolean useNewSeed, boolean randomSeed, String seed);
|
||||
|
||||
boolean isKeepingSpawnInMemory(World world);
|
||||
|
||||
/**
|
||||
* Checks whether Multiverse knows about a provided unloaded world. This
|
||||
* method will check the parameter against the alias mappings.
|
||||
*
|
||||
* @param name The name of the unloaded world
|
||||
* @param includeLoaded The value to return if the world is loaded
|
||||
*
|
||||
* @return True if the world exists and is unloaded. False if the world
|
||||
* does not exist. {@code includeLoaded} if the world exists and is loaded.
|
||||
*/
|
||||
boolean hasUnloadedWorld(String name, boolean includeLoaded);
|
||||
}
|
||||
|
@ -7,15 +7,14 @@
|
||||
|
||||
package com.onarandombox.MultiverseCore.commands;
|
||||
|
||||
import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||
import com.onarandombox.MultiverseCore.api.MVWorldManager;
|
||||
import com.pneumaticraft.commandhandler.CommandHandler;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||
import com.onarandombox.MultiverseCore.api.MVWorldManager;
|
||||
|
||||
/**
|
||||
* Creates a clone of a world.
|
||||
@ -34,27 +33,23 @@ public class CloneCommand extends MultiverseCommand {
|
||||
this.addKey("mv clone");
|
||||
this.addCommandExample("/mv clone " + ChatColor.GOLD + "world" + ChatColor.GREEN + " world_backup");
|
||||
this.addCommandExample("/mv clone " + ChatColor.GOLD + "skyblock_pristine" + ChatColor.GREEN + " skyblock");
|
||||
this.addCommandExample("To clone a world that uses a generator:");
|
||||
this.addCommandExample("/mv clone " + ChatColor.GOLD + "CleanRoom"
|
||||
+ ChatColor.GREEN + " CleanRoomCopy" + ChatColor.DARK_AQUA + " -g CleanRoomGenerator");
|
||||
this.setPermission("multiverse.core.clone", "Clones a world.", PermissionDefault.OP);
|
||||
this.worldManager = this.plugin.getMVWorldManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runCommand(CommandSender sender, List<String> args) {
|
||||
Class<?>[] paramTypes = {String.class, String.class, String.class};
|
||||
List<Object> objectArgs = new ArrayList<Object>();
|
||||
objectArgs.add(args.get(0));
|
||||
objectArgs.add(args.get(1));
|
||||
objectArgs.add(CommandHandler.getFlag("-g", args));
|
||||
if (!this.worldManager.isMVWorld(args.get(0))) {
|
||||
String oldName = args.get(0);
|
||||
if (!this.worldManager.hasUnloadedWorld(oldName, true)) {
|
||||
// If no world was found, we can't clone.
|
||||
sender.sendMessage("Sorry, Multiverse doesn't know about world " + args.get(0) + ", so we can't clone it!");
|
||||
sender.sendMessage("Sorry, Multiverse doesn't know about world " + oldName + ", so we can't clone it!");
|
||||
sender.sendMessage("Check the " + ChatColor.GREEN + "/mv list" + ChatColor.WHITE + " command to verify it is listed.");
|
||||
return;
|
||||
}
|
||||
this.plugin.getCommandHandler().queueCommand(sender, "mvclone", "cloneWorld", objectArgs,
|
||||
paramTypes, ChatColor.GREEN + "World Cloned!", ChatColor.RED + "World could NOT be cloned!");
|
||||
if (this.plugin.getMVWorldManager().cloneWorld(oldName, args.get(1))) {
|
||||
sender.sendMessage(ChatColor.GREEN + "World cloned!");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "World could NOT be cloned!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,30 +7,6 @@
|
||||
|
||||
package com.onarandombox.MultiverseCore.utils;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import com.onarandombox.MultiverseCore.MVWorld;
|
||||
import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||
import com.onarandombox.MultiverseCore.WorldProperties;
|
||||
import com.onarandombox.MultiverseCore.api.MVWorldManager;
|
||||
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
|
||||
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
|
||||
import com.onarandombox.MultiverseCore.api.WorldPurger;
|
||||
import com.onarandombox.MultiverseCore.event.MVWorldDeleteEvent;
|
||||
import com.onarandombox.MultiverseCore.exceptions.PropertyDoesNotExistException;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.WorldType;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
@ -45,7 +21,30 @@ import java.util.Stack;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.WorldType;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import com.onarandombox.MultiverseCore.MVWorld;
|
||||
import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||
import com.onarandombox.MultiverseCore.WorldProperties;
|
||||
import com.onarandombox.MultiverseCore.api.MVWorldManager;
|
||||
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
|
||||
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
|
||||
import com.onarandombox.MultiverseCore.api.WorldPurger;
|
||||
import com.onarandombox.MultiverseCore.event.MVWorldDeleteEvent;
|
||||
|
||||
/**
|
||||
* Public facing API to add/remove Multiverse worlds.
|
||||
@ -93,15 +92,35 @@ public class WorldManager implements MVWorldManager {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @deprecated Use {@link #cloneWorld(String, String)} instead.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean cloneWorld(String oldName, String newName, String generator) {
|
||||
// Make sure we don't already know about the new world.
|
||||
if (this.isMVWorld(newName)) {
|
||||
return false;
|
||||
return this.cloneWorld(oldName, newName);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
}
|
||||
// Make sure the old world is actually a world!
|
||||
if (this.getUnloadedWorlds().contains(oldName) || !this.isMVWorld(oldName)) {
|
||||
if (this.isMVWorld(newName)) {
|
||||
Logging.warning("New world '%s' already exists", newName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -110,63 +129,80 @@ 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);
|
||||
return false;
|
||||
}
|
||||
|
||||
unloadWorld(oldName);
|
||||
|
||||
removePlayersFromWorld(oldName);
|
||||
|
||||
Logging.config("Copying data for world '%s'", oldName);
|
||||
try {
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FileUtils.copyFolder(oldWorldFile, newWorldFile, Logger.getLogger("Minecraft"));
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
try {
|
||||
t.join();
|
||||
} catch (InterruptedException e) {
|
||||
// do nothing
|
||||
// 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);
|
||||
}
|
||||
File uidFile = new File(newWorldFile, "uid.dat");
|
||||
uidFile.delete();
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
if (!this.loadWorld(oldName)) {
|
||||
return false;
|
||||
}
|
||||
this.plugin.getServer().getWorld(oldName).setAutoSave(false);
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// 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, Logging.getLogger())) {
|
||||
Logging.warning("Failed to copy files for world '%s', see the log info", newName);
|
||||
return false;
|
||||
}
|
||||
Logging.fine("Kind of copied stuff");
|
||||
if (oldWorld != null && wasAutoSave) {
|
||||
oldWorld.getCBWorld().setAutoSave(true);
|
||||
}
|
||||
|
||||
WorldCreator worldCreator = new WorldCreator(newName);
|
||||
Logging.fine("Started to copy settings");
|
||||
worldCreator.copy(this.getMVWorld(oldName).getCBWorld());
|
||||
Logging.fine("Copied lots of settings");
|
||||
File uidFile = new File(newWorldFile, "uid.dat");
|
||||
if (uidFile.exists() && !uidFile.delete()) {
|
||||
Logging.warning("Failed to delete unique ID file for world '%s'", newName);
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean useSpawnAdjust = this.getMVWorld(oldName).getAdjustSpawn();
|
||||
Logging.fine("Copied more settings");
|
||||
|
||||
Environment environment = worldCreator.environment();
|
||||
Logging.fine("Copied most settings");
|
||||
if (newWorldFile.exists()) {
|
||||
Logging.fine("Succeeded at copying stuff");
|
||||
if (this.addWorld(newName, environment, null, null, null, generator, useSpawnAdjust)) {
|
||||
Logging.fine("Succeeded at copying files");
|
||||
if (this.addWorld(newName, environment, seedString, worldType, generateStructures, generator, useSpawnAdjust)) {
|
||||
// getMVWorld() doesn't actually return an MVWorld
|
||||
Logging.fine("Succeeded at importing stuff");
|
||||
Logging.fine("Succeeded at importing world");
|
||||
MVWorld newWorld = (MVWorld) this.getMVWorld(newName);
|
||||
MVWorld oldWorld = (MVWorld) this.getMVWorld(oldName);
|
||||
newWorld.copyValues(oldWorld);
|
||||
try {
|
||||
// don't keep the alias the same -- that would be useless
|
||||
newWorld.setPropertyValue("alias", newName);
|
||||
} catch (PropertyDoesNotExistException e) {
|
||||
// this should never happen
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
newWorld.copyValues(this.worldsFromTheConfig.get(oldName));
|
||||
// don't keep the alias the same -- that would be useless
|
||||
newWorld.setAlias(null);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Logging.warning("Failed to copy files for world '%s', see the log info", newName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -846,4 +882,17 @@ public class WorldManager implements MVWorldManager {
|
||||
public FileConfiguration getConfigWorlds() {
|
||||
return this.configWorlds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnloadedWorld(String name, boolean includeLoaded) {
|
||||
if (getMVWorld(name) != null) {
|
||||
return includeLoaded;
|
||||
}
|
||||
for (Map.Entry<String, WorldProperties> entry : this.worldsFromTheConfig.entrySet()) {
|
||||
if (name.equals(entry.getKey()) || name.equals(entry.getValue().getAlias())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user