From f57468126aa103853a89499a9f8991c4884e130a Mon Sep 17 00:00:00 2001 From: Matt H Date: Wed, 18 Jul 2012 20:36:27 -0600 Subject: [PATCH] Added '/mv clone' command to clone a world. --- .../MultiverseCore/MultiverseCore.java | 15 ++++ .../MultiverseCore/api/MVWorldManager.java | 11 +++ .../MultiverseCore/commands/CloneCommand.java | 59 +++++++++++++ .../MultiverseCore/utils/WorldManager.java | 82 +++++++++++++++++++ src/main/resources/plugin.yml | 5 ++ 5 files changed, 172 insertions(+) create mode 100644 src/main/java/com/onarandombox/MultiverseCore/commands/CloneCommand.java diff --git a/src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java b/src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java index 6f83d825..1067a25f 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java +++ b/src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java @@ -21,6 +21,7 @@ import com.onarandombox.MultiverseCore.api.MultiverseWorld; import com.onarandombox.MultiverseCore.api.SafeTTeleporter; import com.onarandombox.MultiverseCore.commands.AnchorCommand; import com.onarandombox.MultiverseCore.commands.CheckCommand; +import com.onarandombox.MultiverseCore.commands.CloneCommand; import com.onarandombox.MultiverseCore.commands.ConfigCommand; import com.onarandombox.MultiverseCore.commands.ConfirmCommand; import com.onarandombox.MultiverseCore.commands.CoordCommand; @@ -656,6 +657,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { this.commandHandler.registerCommand(new ListCommand(this)); this.commandHandler.registerCommand(new InfoCommand(this)); this.commandHandler.registerCommand(new CreateCommand(this)); + this.commandHandler.registerCommand(new CloneCommand(this)); this.commandHandler.registerCommand(new ImportCommand(this)); this.commandHandler.registerCommand(new ReloadCommand(this)); this.commandHandler.registerCommand(new SetSpawnCommand(this)); @@ -1028,6 +1030,19 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { return this.worldManager.deleteWorld(name); } + /** + * NOT deprecated for the time as queued commands use this. + * However, this is not in the API and other plugins should therefore not use it. + * + * @param oldName World to copy + * @param newName World to create + * @param generator The Custom generator plugin to use. + * @return True if success, false if fail. + */ + public Boolean cloneWorld(String oldName, String newName, String generator) { + return this.worldManager.cloneWorld(oldName, newName, generator); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/onarandombox/MultiverseCore/api/MVWorldManager.java b/src/main/java/com/onarandombox/MultiverseCore/api/MVWorldManager.java index f13da921..8d280c30 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/api/MVWorldManager.java +++ b/src/main/java/com/onarandombox/MultiverseCore/api/MVWorldManager.java @@ -60,6 +60,17 @@ public interface MVWorldManager { boolean addWorld(String name, Environment env, String seedString, WorldType type, Boolean generateStructures, String generator, boolean useSpawnAdjust); + /** + * Make a copy of a world. + * + * @param oldName Name of world to be copied + * @param newName Name of world to be created + * @param env Environment Type + * @param generator The Custom generator plugin to use. + * @return True if the world is copied successfully, false if not. + */ + boolean cloneWorld(String oldName, String newName, String generator); + /** * Remove the world from the Multiverse list, from the * config and deletes the folder. diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/CloneCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/CloneCommand.java new file mode 100644 index 00000000..325e77f8 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/CloneCommand.java @@ -0,0 +1,59 @@ +/****************************************************************************** + * Multiverse 2 Copyright (c) the Multiverse Team 2011. * + * Multiverse 2 is licensed under the BSD License. * + * For more information please check the README.md file included * + * with this project. * + ******************************************************************************/ + +package com.onarandombox.MultiverseCore.commands; + +import com.onarandombox.MultiverseCore.MultiverseCore; +import com.onarandombox.MultiverseCore.api.MVWorldManager; +import com.pneumaticraft.commandhandler.CommandHandler; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.permissions.PermissionDefault; + +import java.util.ArrayList; +import java.util.List; + +/** + * Creates a clone of a world. + */ +public class CloneCommand extends MultiverseCommand { + private MVWorldManager worldManager; + + public CloneCommand(MultiverseCore plugin) { + super(plugin); + this.setName("Clone World"); + this.setCommandUsage("/mv clone" + ChatColor.GREEN + " {TARGET} {NAME}" + ChatColor.GOLD + " -g [GENERATOR[:ID]]"); + this.setArgRange(2, 4); // SUPPRESS CHECKSTYLE: MagicNumberCheck + this.addKey("mvclone"); + this.addKey("mvcl"); + this.addKey("mv cl"); + 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 args) { + Class[] paramTypes = {String.class, String.class, String.class}; + List objectArgs = new ArrayList(); + objectArgs.add(args.get(0)); + objectArgs.add(args.get(1)); + objectArgs.add(CommandHandler.getFlag("-g", args)); + if (!this.worldManager.isMVWorld(args.get(0))) { + // 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("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!"); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/WorldManager.java b/src/main/java/com/onarandombox/MultiverseCore/utils/WorldManager.java index f8e018fb..d92c9e6a 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/WorldManager.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/WorldManager.java @@ -14,6 +14,7 @@ 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.World; import org.bukkit.World.Environment; import org.bukkit.WorldCreator; @@ -38,6 +39,7 @@ import java.util.Map; import java.util.Set; import java.util.Stack; import java.util.logging.Level; +import java.util.logging.Logger; /** * Public facing API to add/remove Multiverse worlds. @@ -83,6 +85,86 @@ public class WorldManager implements MVWorldManager { } } + /** + * {@inheritDoc} + */ + @Override + 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; + } + // Make sure the old world is actually a world! + if (this.getUnloadedWorlds().contains(oldName) || !this.isMVWorld(oldName)) { + return false; + } + + final File oldWorldFile = new File(this.plugin.getServer().getWorldContainer(), oldName); + final File newWorldFile = new File(this.plugin.getServer().getWorldContainer(), newName); + + // Make sure the new world doesn't exist outside of multiverse. + if (newWorldFile.exists()) { + return false; + } + + unloadWorld(oldName); + + removePlayersFromWorld(oldName); + + StringBuilder builder = new StringBuilder(); + builder.append("Copying data for world '").append(oldName).append("'..."); + this.plugin.log(Level.INFO, builder.toString()); + try { + Thread t = new Thread(new Runnable() { + public void run() { + FileUtils.copyFolder(oldWorldFile, newWorldFile, Logger.getLogger("Minecraft")); + } + }); + t.start(); + try { + t.join(); + } catch (InterruptedException e) { + // do nothing + } + File uidFile = new File(newWorldFile, "uid.dat"); + uidFile.delete(); + } catch (NullPointerException e) { + e.printStackTrace(); + return false; + } + this.plugin.log(Level.INFO, "Kind of copied stuff"); + + WorldCreator worldCreator = new WorldCreator(newName); + this.plugin.log(Level.INFO, "Started to copy settings"); + worldCreator.copy(this.getMVWorld(oldName).getCBWorld()); + this.plugin.log(Level.INFO, "Copied lots of settings"); + + boolean useSpawnAdjust = this.getMVWorld(oldName).getAdjustSpawn(); + this.plugin.log(Level.INFO, "Copied more settings"); + + Environment environment = worldCreator.environment(); + this.plugin.log(Level.INFO, "Copied most settings"); + if (newWorldFile.exists()) { + this.plugin.log(Level.INFO, "Succeeded at copying stuff"); + if (this.addWorld(newName, environment, null, null, null, generator, useSpawnAdjust)) { + // getMVWorld() doesn't actually return an MVWorld + this.plugin.log(Level.INFO, "Succeeded at importing stuff"); + 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); + } + return true; + } + } + return false; + } + /** * {@inheritDoc} */ diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 83fd8205..79ac2a9e 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -206,3 +206,8 @@ commands: description: Runs a script from the Multiverse scripts directory. usage: | / {script} [target] + mvclone: + description: World clone command + usage: | + / + / creative grieftastic -- Creates a world called 'grieftastic' exactly identical to the world 'creative'.