Error while copying world folder

Discussion in 'Plugin Development' started by ThunderWaffeMC, Jul 8, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    ThunderWaffeMC

    I'm getting an internal error on the command. I'm trying to copy the world folder (CollideTemplate) and paste it with the name of the player.

    My code:

    Code:java
    1.  
    2. if (args.length == 1) {
    3. if (args[0].equalsIgnoreCase("start")) {
    4. if (!player.hasPermission("collide.start")) {
    5. getLogger().fine("Player " + player.getName() + " has no collide.start permission.");
    6. player.sendMessage(ChatColor.BLUE + "[Collide]" + ChatColor.RED + " You do not have permission to use this command!");
    7. return false;
    8. }
    9. World template = Bukkit.getWorld("CollideTemplate");
    10. World playerworld = Bukkit.getWorld(player.getName() + "-world");
    11. String templateName = "CollideTemplate";//enter template world's name
    12. String newWorldName = player.getName() + "-world";//name of the world thats going to be made
    13.  
    14. File serverFolder = new File(System.getProperty("user.dir"));//server directory
    15. File templateFolder = new File(serverFolder + File.separator + templateName);//template world directory
    16. File newWorldFolder = new File(serverFolder + File.separator + newWorldName);//new player world directory
    17.  
    18. if (template!=null) {Bukkit.unloadWorld(template, true);}
    19. if (template==null) {player.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "ERROR #101: Unable to find base template world! Report to a MUOSU staff member." + " Current world: " + ChatColor.GOLD + player.getWorld().getName()); return false;}
    20.  
    21. if (!(playerworld==null)){
    22. sender.sendMessage(ChatColor.YELLOW + "" + ChatColor.GOLD + "" + ChatColor.YELLOW + "");
    23. sender.sendMessage(ChatColor.YELLOW + "---" + ChatColor.GOLD + "Collide Base Generation " + ChatColor.GREEN + "In Process!" + ChatColor.YELLOW + "---");
    24. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "ERROR #102");
    25. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "You already have a base!");
    26. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "Use /collide home or /collide delete.");
    27. sender.sendMessage(ChatColor.YELLOW + "---" + ChatColor.GOLD + "Collide Base Generation " + ChatColor.RED + "Failed!" + ChatColor.YELLOW + "---");
    28. return false;
    29. }
    30.  
    31. sender.sendMessage(ChatColor.YELLOW + "" + ChatColor.GOLD + "" + ChatColor.YELLOW + "");
    32. sender.sendMessage(ChatColor.YELLOW + "---" + ChatColor.GOLD + "Collide Base Generation " + ChatColor.GREEN + "In Process!" + ChatColor.YELLOW + "---");
    33. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "Creating folders... Please wait!");//create folders
    34.  
    35. if (!newWorldFolder.exists()){
    36. newWorldFolder.mkdir();
    37. new File(newWorldFolder.getPath() + File.separator + "data").mkdirs();
    38. new File(newWorldFolder.getPath() + File.separator + "players").mkdirs();
    39. new File(newWorldFolder.getPath() + File.separator + "region").mkdirs();
    40. }
    41.  
    42. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "Copying world data... Please wait!");//copy files into the folders
    43. try {
    44. Files.copy(new File(templateFolder.getPath() + File.separator + "data"), new File(newWorldFolder.getPath() + File.separator + "data"));
    45. Files.copy(new File(templateFolder.getPath() + File.separator + "region"), new File(newWorldFolder.getPath() + File.separator + "region"));
    46. Files.copy(templateFolder, newWorldFolder);
    47. } catch (IOException e) {
    48. e.printStackTrace();
    49. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "ERROR! Please wait!");
    50. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "There was an error on world copy! Please report the following to staff:");
    51. getLogger().info("Server: "+serverFolder.getPath());
    52. getLogger().info("From: "+templateFolder.getPath());
    53. getLogger().info("To: "+newWorldFolder.getPath());
    54. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.GOLD + "Server: " + ChatColor.RED + serverFolder.getPath());
    55. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.GOLD + "From: " + ChatColor.RED + templateFolder.getPath());
    56. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.GOLD + "To: " + ChatColor.RED + newWorldFolder.getPath());
    57. sender.sendMessage(ChatColor.YELLOW + "---" + ChatColor.GOLD + "Collide Base Generation " + ChatColor.RED + "Failed!" + ChatColor.YELLOW + "---");
    58. return true;//ends command on error
    59. }
    60.  
    61. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "Preventing problems... Please wait!");//remove the copied id so it can load properly
    62. File CopiedWorldUID = new File(newWorldFolder + File.separator + "uid.dat");
    63. if (CopiedWorldUID.exists()) {CopiedWorldUID.delete();}
    64.  
    65. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "Loading world... Please wait!");//tells Bukkit to create the world with the same data as the template
    66. Bukkit.createWorld(new WorldCreator(templateName).copy(template));//this will let Bukkit load it and have the same seed for generation
    67.  
    68.  
    69. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "Your base has been created!");
    70. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "Use /collide home.");
    71. sender.sendMessage(ChatColor.YELLOW + "---" + ChatColor.GOLD + "Collide Base Generation " + ChatColor.GREEN + "Complete!" + ChatColor.YELLOW + "---");
    72. }
    73. }
    74.  


    Error:

    Code:
    2013-07-09 13:13:34 [INFO] Thunder_Waffe issued server command: /collide start
    2013-07-09 13:13:35 [SEVERE] java.io.FileNotFoundException: C:\Users\Toshiba\Documents\zServers\Collide Server\CollideTemplate\data (Access is denied)
    2013-07-09 13:13:35 [SEVERE]     at java.io.FileInputStream.open(Native Method)
    2013-07-09 13:13:35 [SEVERE]     at java.io.FileInputStream.<init>(Unknown Source)
    2013-07-09 13:13:35 [SEVERE]     at com.google.common.io.Files$1.getInput(Files.java:100)
    2013-07-09 13:13:35 [SEVERE]     at com.google.common.io.Files$1.getInput(Files.java:97)
    2013-07-09 13:13:35 [SEVERE]     at com.google.common.io.ByteStreams.copy(ByteStreams.java:116)
    2013-07-09 13:13:35 [SEVERE]     at com.google.common.io.Files.copy(Files.java:231)
    2013-07-09 13:13:35 [SEVERE]     at com.google.common.io.Files.copy(Files.java:277)
    2013-07-09 13:13:35 [SEVERE]     at com.gmail.thunderwaffemc.Collide.onCommand(Collide.java:238)
    2013-07-09 13:13:35 [SEVERE]     at org.bukkit.command.PluginCommand.execute(PluginCommand.java:44)
    2013-07-09 13:13:35 [SEVERE]     at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:189)
    2013-07-09 13:13:35 [SEVERE]     at org.bukkit.craftbukkit.v1_6_R2.CraftServer.dispatchCommand(CraftServer.java:523)
    2013-07-09 13:13:35 [SEVERE]     at net.minecraft.server.v1_6_R2.PlayerConnection.handleCommand(PlayerConnection.java:964)
    2013-07-09 13:13:35 [SEVERE]     at net.minecraft.server.v1_6_R2.PlayerConnection.chat(PlayerConnection.java:882)
    2013-07-09 13:13:35 [SEVERE]     at net.minecraft.server.v1_6_R2.PlayerConnection.a(PlayerConnection.java:839)
    2013-07-09 13:13:35 [SEVERE]     at net.minecraft.server.v1_6_R2.Packet3Chat.handle(SourceFile:49)
    2013-07-09 13:13:35 [SEVERE]     at net.minecraft.server.v1_6_R2.NetworkManager.b(NetworkManager.java:296)
    2013-07-09 13:13:35 [SEVERE]     at net.minecraft.server.v1_6_R2.PlayerConnection.e(PlayerConnection.java:118)
    2013-07-09 13:13:35 [SEVERE]     at net.minecraft.server.v1_6_R2.ServerConnection.b(SourceFile:37)
    2013-07-09 13:13:35 [SEVERE]     at net.minecraft.server.v1_6_R2.DedicatedServerConnection.b(SourceFile:30)
    2013-07-09 13:13:35 [SEVERE]     at net.minecraft.server.v1_6_R2.MinecraftServer.t(MinecraftServer.java:590)
    2013-07-09 13:13:35 [SEVERE]     at net.minecraft.server.v1_6_R2.DedicatedServer.t(DedicatedServer.java:226)
    2013-07-09 13:13:35 [SEVERE]     at net.minecraft.server.v1_6_R2.MinecraftServer.s(MinecraftServer.java:486)
    2013-07-09 13:13:35 [SEVERE]     at net.minecraft.server.v1_6_R2.MinecraftServer.run(MinecraftServer.java:419)
    2013-07-09 13:13:35 [SEVERE]     at net.minecraft.server.v1_6_R2.ThreadServerApplication.run(SourceFile:582)
    2013-07-09 13:13:35 [INFO] [Collide] Server: C:\Users\Toshiba\Documents\zServers\Collide Server
    2013-07-09 13:13:35 [INFO] [Collide] From: C:\Users\Toshiba\Documents\zServers\Collide Server\CollideTemplate
    2013-07-09 13:13:35 [INFO] [Collide] To: C:\Users\Toshiba\Documents\zServers\Collide Server\Thunder_Waffe-world
    
    Any help is appreciated! Thanks!
     
  2. Offline

    LinearLogic

    There's a runtime file lock on certain files and folders used by CraftBukkit, including worlds. You can't edit or move world directories after the worlds have been loaded, which occurs before your plugin's onEnable() method is called. Override the onLoad() method and put your file operations there instead.
     
  3. Offline

    tills13

    > (Access is denied)

    CollideTemplate/data is a directory, you cannot open a directory with FileInputStream.
     
  4. Offline

    ThunderWaffeMC

  5. Offline

    tills13

    well ... just throwing an idea out there, but:
    Code:java
    1. public void copy(File curDir, String destination) {
    2. for (File file : curDir.listFileS()) {
    3. if (file.isDirectory()) copy(file, destination + file.getName());
    4. else Files.copy(file.getAbsolutePath(), new FileOutputStream(new File(destination + file.getName())));
    5. }
    6. }


    I believe that will work.
     
    ThunderWaffeMC likes this.
  6. Offline

    LinearLogic

    If you aren't actually editing the world folder or its contents, the above method should suffice. Otherwise, put the same method in onLoad() instead of onEnable() to circumnavigate the file lock issue.
     
    ThunderWaffeMC likes this.
  7. Offline

    tills13

    That doesn't actually work...

    This does, though:
    Code:java
    1. public static void copy(File curDir, String destination) {
    2. try {
    3. for (File file : curDir.listFiles()) {
    4. if (file.isDirectory()) {
    5. if (!new File(destination + File.separator + file.getName()).exists()) new File(destination + File.separator + file.getName()).mkdir();
    6. copy(file, destination + File.separator + file.getName());
    7. } else {
    8. Path path = FileSystems.getDefault().getPath(curDir.getPath(), file.getName());
    9. if (!new File(destination).exists()) new File(destination).mkdir();
    10. Files.copy(path, new FileOutputStream(new File(destination + File.separator + file.getName())));
    11. }
    12. }
    13. } catch (FileNotFoundException e) {
    14. System.out.println("File not found: " + e.getMessage());
    15. } catch (IOException e) {
    16. System.out.println("IO error: " + e.getMessage());
    17. }
    18. }
     
  8. Offline

    ThunderWaffeMC

    I get an error in eclipse on "copy" from:

    Code:java
    1.  
    2. else Files.copy(file.getAbsolutePath(), new FileOutputStream(new File(destination + file.getName())));
    3.  


    Saying: The method copy(InputSupplier<? extends InputStream>, File) in the type Files is not applicable for the arguments (String, FileOutputStream)

    Any idea?
     
  9. Offline

    tills13

    I just posted an update.

    Import these:

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.FileSystems;

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 3, 2016
  10. Offline

    LinearLogic

    If that doesn't work (but it looks just fine), below is what I'm using in a number of my plugins. It simply copies file contents use a byte buffer instead of the java.nio utils (I like to minimize imports and dependencies where I can), but both should perform on par.
    Code:
    private static void copyDir(File source, File target) throws IOException {
        if(source.isDirectory()) {
            if(!target.exists())
              target.mkdirs();
            String files[] = source.list();
            for (String file : files) {
              File srcFile = new File(source, file);
              File destFile = new File(target, file);
              copyDir(srcFile, destFile);
            }
        } else {
            InputStream in = new FileInputStream(source);
            OutputStream out = new FileOutputStream(target);
            byte[] buffer = new byte[1024];
            int length;
            //copy the file content in bytes
            while ((length = in.read(buffer)) > 0)
                out.write(buffer, 0, length);
            in.close();
            out.close();
        }
    }
     
    ThunderWaffeMC likes this.
  11. Offline

    ThunderWaffeMC

    But I want to copy it on command? Is there any way to fix my code without having to replace it or doing something entirely new?
     
  12. Offline

    LinearLogic

    Are you trying to copy the world folder elsewhere?
     
  13. Offline

    ThunderWaffeMC

    No. I'm trying to copy the template (CollideTemplate) from my bukkit worlds and paste it in the same directory but rename it as <PlayerName>-world as seen in my code.

    PS. I appreciate the help.
     
  14. Offline

    tills13

    Yeah. So you would just replace this block in yours:
    Code:java
    1. try {
    2. Files.copy(new File(templateFolder.getPath() + File.separator + "data"), new File(newWorldFolder.getPath() + File.separator + "data"));
    3. Files.copy(new File(templateFolder.getPath() + File.separator + "region"), new File(newWorldFolder.getPath() + File.separator + "region"));
    4. Files.copy(templateFolder, newWorldFolder);
    5. } catch (IOException e) {
    6. e.printStackTrace();
    7. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "ERROR! Please wait!");
    8. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.RED + "There was an error on world copy! Please report the following to staff:");
    9. getLogger().info("Server: "+serverFolder.getPath());
    10. getLogger().info("From: "+templateFolder.getPath());
    11. getLogger().info("To: "+newWorldFolder.getPath());
    12. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.GOLD + "Server: " + ChatColor.RED + serverFolder.getPath());
    13. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.GOLD + "From: " + ChatColor.RED + templateFolder.getPath());
    14. sender.sendMessage(ChatColor.BLUE + "[Collide] " + ChatColor.GOLD + "To: " + ChatColor.RED + newWorldFolder.getPath());
    15. sender.sendMessage(ChatColor.YELLOW + "---" + ChatColor.GOLD + "Collide Base Generation " + ChatColor.RED + "Failed!" + ChatColor.YELLOW + "---");
    16. return true;//ends command on error
    17. }


    with a simple call to either:
    Code:
    copy(templateFolder, newWorldFolder.getPath());
    or
    Code:
    copyDir(templateFolder, newWorldFolder.);
    depending on which method you'd like to use.
     
    ThunderWaffeMC likes this.
  15. Offline

    LinearLogic

    ThunderWaffeMC, I went ahead and wrote a plugin that achieves what I think you're trying to do (when I run /collide start, it creates a world folder in my server directory called LinearLogic-world, based off of a world folder called TemplateWorld). I cut out some of what you had for expediency. Let me know if this helps:
    Code:java
    1. public class Collide extends JavaPlugin {
    2.  
    3. public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
    4. if (!cmd.getName().equalsIgnoreCase("collide"))
    5. return true;
    6. if (args.length == 1 && args[0].equalsIgnoreCase("start")) {
    7. if (!(sender instanceof Player)) {
    8. sender.sendMessage(ChatColor.RED + "This command is only available to players!");
    9. return true;
    10. }
    11.  
    12. Player player = (Player) sender;
    13. if (!player.hasPermission("collide.start")) {
    14. getLogger().fine("Player " + player.getName() + " has no collide.start permission.");
    15. player.sendMessage(ChatColor.BLUE + "[Collide]" + ChatColor.RED + " You do not have permission to use this command!");
    16. return true;
    17. }
    18.  
    19. // As far as I can tell, you only retrieve the World objects in order to unload them,
    20. // which won't alleviate the issue anyway, so I skip straight to the file operations:
    21. File templateWorldFolder = new File(getServer().getWorldContainer(), "world");
    22. if (!templateWorldFolder.exists() || !templateWorldFolder.isDirectory()) {
    23. // The template world is missing - abort the operation
    24. player.sendMessage(ChatColor.RED + "Could not locate the template world - contact your administrator.");
    25. return true;
    26. }
    27. File playerWorldFolder = new File(getServer().getWorldContainer(), player.getName() + "-world");
    28. if (playerWorldFolder.exists()) {
    29. // The world has already been created
    30. player.sendMessage(ChatColor.RED + "You already have a base!");
    31. return true;
    32. }
    33. try {
    34. copyDir(templateWorldFolder, playerWorldFolder);
    35. } catch (IOException e) {
    36. player.sendMessage(ChatColor.RED + "Failed to create base world - error whilse copying template directory!");
    37. return true;
    38. }
    39. player.sendMessage(ChatColor.GREEN + "Successfully created your base world!");
    40. return true;
    41. }
    42. // Handle other subcommands here...
    43. return true;
    44. }
    45.  
    46. private static void copyDir(File source, File target) throws IOException {
    47. if(source.isDirectory()) {
    48. if(!target.exists())
    49. target.mkdirs();
    50. String files[] = source.list();
    51. for (String file : files) {
    52. File srcFile = new File(source, file);
    53. File destFile = new File(target, file);
    54. copyDir(srcFile, destFile);
    55. }
    56. } else {
    57. InputStream in = new FileInputStream(source);
    58. OutputStream out = new FileOutputStream(target);
    59. byte[] buffer = new byte[1024];
    60. int length;
    61. //copy the file content in bytes
    62. while ((length = in.read(buffer)) > 0)
    63. out.write(buffer, 0, length);
    64. in.close();
    65. out.close();
    66. }
    67. }
    68. }
     
    ThunderWaffeMC likes this.
  16. Offline

    ThunderWaffeMC

    WOW! Thanks so much! Is there a way to not copy some files? I only want to copy the 3 folders inside the world folder (data, region and players) and not the uid.dat. Or I could delete the uid.dat after creation but is there a way to not copy the uid.dat?
     
  17. Offline

    tills13

    Here's my method modified to account for something like that:

    Code:
    public static void copy(File curDir, String destination) {
            ArrayList<String> ignore = new ArrayList<String>(Arrays.asList("uid.dat", "level.dat", "session.dat"));
            try {
                for (File file : curDir.listFiles()) {
                    System.out.println(file.getName());
                    if (!ignore.contains(file.getName())) {
                        if (file.isDirectory()) {
                            if (!new File(destination + File.separator + file.getName()).exists()) new File(destination + File.separator + file.getName()).mkdir();
                            copy(file, destination + File.separator + file.getName());
                        } else {
                            Path path = FileSystems.getDefault().getPath(curDir.getPath(), file.getName());
                            if (!new File(destination).exists()) new File(destination).mkdir();
                            Files.copy(path, new FileOutputStream(new File(destination + File.separator + file.getName())));
                        }
                    }
                }   
            } catch (FileNotFoundException e) {
                System.out.println("File not found: " + e.getMessage());
            } catch (IOException e) {
                System.out.println("IO error: " + e.getMessage());
            }
        }
    Notice the ArrayList line with the files to ignore and the if statement ignore.contains(file.getName())

    It works with directories, as well.

    Here's LinearLogic's function modified:
    Code:
    private static void copyDir(File source, File target) {
            try {
                ArrayList<String> ignore = new ArrayList<String>(Arrays.asList("uid.dat", "level.dat", "session.dat", "data"));
                if (!ignore.contains(source.getName())) {
                    if(source.isDirectory()) {
                        if(!target.exists())
                          target.mkdirs();
                        String files[] = source.list();
                        for (String file : files) {
                          File srcFile = new File(source, file);
                          File destFile = new File(target, file);
                          copyDir(srcFile, destFile);
                        }
                    } else {
                        InputStream in = new FileInputStream(source);
                        OutputStream out = new FileOutputStream(target);
                        byte[] buffer = new byte[1024];
                        int length;
                        //copy the file content in bytes
                        while ((length = in.read(buffer)) > 0)
                            out.write(buffer, 0, length);
                        in.close();
                        out.close();
                    }
                }
            } catch (IOException e) {
     
            }
        }
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 3, 2016
    ThunderWaffeMC likes this.
  18. Offline

    ThunderWaffeMC

    Thanks very much! Much appreciated!
     
Thread Status:
Not open for further replies.

Share This Page