TerrainManager: backing up/restoring terrain made easier

Discussion in 'Resources' started by desht, Jul 2, 2012.

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

    desht

    Question on how to back up or restore an area of terrain to a schematic file are very common in the Plugin Development section, and it's something I do in my ChessCraft plugin, so I thought I'd generalise the code out into a more re-usable class. So I present: https://github.com/desht/dhutils/blob/master/Lib/src/main/java/me/desht/dhutils/TerrainManager.java

    It hooks the WorldEdit API, so WorldEdit will need to be present at run-time for this to be used sucessfully, and your plugin will of course need to be built against WorldEdit if you include TerrainManager.jar directly (I build this as part of dhutils.jar - a collection of utility classes - using Maven, and then build my plugins against dhutils, again with Maven).

    I've built against WorldEdit 5.3 and now 5.5.8, but newer releases should be fine - older releases will probably not work.

    Here's how you might use it:
    PHP:
    Location l1 // Location representing one corner of the region
    Location l2 // Location representing the corner opposite to <l1>
    // ensure WorldEdit is available
    WorldEditPlugin wep = (WorldEditPlugin)Bukkit.getPluginManager.getPlugin("WorldEdit");
    if (
    wep == null) {
      
    // then don't try to use TerrainManager!
    }
     
    // create a terrain manager object
    TerrainManager tm = new TerrainManager(wepplayer);
    // OR - without needing an associated Player
    TerrainManager tm = new TerrainManager(wepworld);
     
    // don't include an extension - TerrainManager will auto-add ".schematic"
    File saveFile = new File(plugin.getDataFolder(), "backup1");
     
    // save the terrain to a schematic file
    try {
      
    tm.saveTerrain(saveFilel1l2);
    } catch (
    FilenameException e) {
      
    // thrown by WorldEdit - it doesn't like the file name/location etc.
    } catch (DataException e) {
      
    // thrown by WorldEdit - problem with the data
    } catch (IOException e) {
      
    // problem with creating/writing to the file
    }
     
    // reload a schematic
    try {
      
    // reload at the given location
      
    Location location = new Location(xyz);
      
    tm.loadSchematic(saveFilelocation);
      
    // OR
      // reload at the same place it was saved
      
    tm.loadSchematic(saveFile);
    } catch (
    FilenameException e) {
      
    // thrown by WorldEdit - it doesn't like the file name/location etc.
    } catch (DataException e) {
      
    // thrown by WorldEdit - problem with the data
    } catch (IOException e) {
      
    // problem with opening/reading the file
    } catch (MaxChangedBlocksException e) {
      
    // thrown by WorldEdit - the schematic is larger than the configured block limit for the player
    } catch (EmptyClipboardException e) {
    // thrown by WorldEdit - should be self-explanatory
    }
    Hopefully clear enough. There are a lot of exceptions to catch, but then there's a lot that could go wrong!

    For an example of a plugin that uses this class: https://github.com/desht/ChessCraft...me/desht/chesscraft/blocks/TerrainBackup.java. Note my slightly cheaty "catch(Exception e)" code there for brevity :)

    Also: don't forget to add a dependency (softdepend: WorldEdit or depend: WorldEdit) in your plugin.yml!

    Licensing: TerrainManager is licensed under the LGPL. You're welcome to use the class in your plugin, but please give credit where it's due. Your plugin doesn't need to be GPL-licensed or anything, but you will need to provide the (possibly modified) source to TerrainManager upon request.
     
    DogisPlz, Gfegyver, Conlexio and 7 others like this.
  2. Offline

    MrMag518

    Thanks, I needed this! :)
     
  3. Offline

    Jakeob22

    Perfect for what I need. ;)
     
  4. Offline

    chaseoes

    desht Getting this when attempting to use:
    Code:
    2012-08-21 20:12:11 [SEVERE] java.lang.NullPointerException
    2012-08-21 20:12:11 [SEVERE]     at com.sk89q.worldedit.WorldEdit.getSafeFile(WorldEdit.java:750)
    2012-08-21 20:12:11 [SEVERE]     at com.sk89q.worldedit.WorldEdit.getSafeSaveFile(WorldEdit.java:684)
    2012-08-21 20:12:11 [SEVERE]     at me.chaseoes.skyblocksurvival.schematics.TerrainManager.loadSchematic(TerrainManager.java:102)
    2012-08-21 20:12:11 [SEVERE]     at me.chaseoes.skyblocksurvival.SkyBlockSurvival.onCommand(SkyBlockSurvival.java:36)
    2012-08-21 20:12:11 [SEVERE]     at org.bukkit.command.PluginCommand.execute(PluginCommand.java:40)
    2012-08-21 20:12:11 [SEVERE]     at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:168)
    2012-08-21 20:12:11 [SEVERE]     at org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:492)
    2012-08-21 20:12:11 [SEVERE]     at net.minecraft.server.NetServerHandler.handleCommand(NetServerHandler.java:878)
    2012-08-21 20:12:11 [SEVERE]     at net.minecraft.server.NetServerHandler.chat(NetServerHandler.java:825)
    2012-08-21 20:12:11 [SEVERE]     at net.minecraft.server.NetServerHandler.a(NetServerHandler.java:807)
    2012-08-21 20:12:11 [SEVERE]     at net.minecraft.server.Packet3Chat.handle(Packet3Chat.java:44)
    2012-08-21 20:12:11 [SEVERE]     at net.minecraft.server.NetworkManager.b(NetworkManager.java:276)
    2012-08-21 20:12:11 [SEVERE]     at net.minecraft.server.NetServerHandler.d(NetServerHandler.java:109)
    2012-08-21 20:12:11 [SEVERE]     at net.minecraft.server.ServerConnection.b(SourceFile:35)
    2012-08-21 20:12:11 [SEVERE]     at net.minecraft.server.DedicatedServerConnection.b(SourceFile:30)
    2012-08-21 20:12:11 [SEVERE]     at net.minecraft.server.MinecraftServer.q(MinecraftServer.java:581)
    2012-08-21 20:12:11 [SEVERE]     at net.minecraft.server.DedicatedServer.q(DedicatedServer.java:212)
    2012-08-21 20:12:11 [SEVERE]     at net.minecraft.server.MinecraftServer.p(MinecraftServer.java:474)
    2012-08-21 20:12:11 [SEVERE]     at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:406)
    2012-08-21 20:12:11 [SEVERE]     at net.minecraft.server.ThreadServerApplication.run(SourceFile:539)
     
  5. Offline

    desht

  6. Offline

    chaseoes

    Code:
        WorldEditPlugin wep = null;
        File saveFile = new File(getDataFolder(), "schematic");
     
        public void onEnable() {
            wep = (WorldEditPlugin)getServer().getPluginManager().getPlugin("WorldEdit");
        }
     
            // Command
            if (cmnd.getName().equalsIgnoreCase("create")) {
                Player player = (Player) cs;
                if (strings[0].equalsIgnoreCase("createnew")) {
                    TerrainManager tm = new TerrainManager(wep, player);
                    try {
                        tm.loadSchematic(saveFile, player.getLocation());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
     
  7. Offline

    desht

    chaseoes looks ok but I'm on a mobile device right now so can't look deeper. I just pass the save file through to WorldEdit's getSafeSaveFile() method, so it might be worth checking the WE source to see what it's doing at the NPE line.
     
  8. Offline

    TMAsantos

    I haveThis error :S
    PHP:
    15:31:59 [SEVERE]      at java.io.FileInputStream.open(Native Method)
    15:31:59 [SEVERE]      at java.io.FileInputStream.<init>(FileInputStream.java:120)
    15:31:59 [SEVERE]      at com.sk89q.worldedit.schematic.MCEditSchematicFormat.load(MCEditSchematicFormat.java:61)
    15:31:59 [SEVERE]      at me.tmasantos.Battle2.Material.TerrainManager.loadSchematic(TerrainManager.java:107)
    15:31:59 [SEVERE]      at me.tmasantos.Battle2.Material.TerrainManager.loadSchematic(TerrainManager.java:124)
    15:31:59 [SEVERE]      at me.tmasantos.Battle2.Material.PrivateScheduler$1.run(PrivateScheduler.java:60)
    15:31:59 [SEVERE]      at org.bukkit.craftbukkit.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:126)
    15:31:59 [SEVERE]      at net.minecraft.server.MinecraftServer.q(MinecraftServer.java:510)
    15:31:59 [SEVERE]      at net.minecraft.server.DedicatedServer.q(DedicatedServer.java:212)
    15:31:59 [SEVERE]      at net.minecraft.server.MinecraftServer.p(MinecraftServer.java:474)
    15:31:59 [SEVERE]      at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:406)
    15:31:59 [SEVERE]      at net.minecraft.server.ThreadServerApplication.run(SourceFile:539)
    desht Is it up to date? with the new schematic system?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 26, 2016
  9. Offline

    desht

    This is only a thin wrapper around some WorldEdit calls, so your question really needs to be directed to the WE team.
     
  10. Offline

    chaseoes

    What happens if one gets pasted into an area of the world that hasn't been generated yet? When you finally visit that location and the chunks etc. load will the default world generator take over and just replace it?
     
  11. Offline

    desht

    My understanding is that any attempt to get or change the contents of a block will implicitly force the chunk for that block to be loaded (and, if necessary, generated). So when you visit the location, it should still maintain the contents that you pasted there.
     
  12. Offline

    Eballer48


    This still work?

    Getting this error:

    Code:
    2013-05-13 12:12:22 [WARNING] [SimpleSpleef] Task #26 for SimpleSpleef v4.3 generated an exception
    java.lang.NullPointerException
    at com.sk89q.worldedit.bukkit.BukkitPlayer.getName(BukkitPlayer.java:54)
    at com.sk89q.worldedit.WorldEdit.getSession(WorldEdit.java:312)
    at me.BlahBerrys.SimpleSpleef.util.TerrainManager.<init>(TerrainManager.java:49)
    at me.BlahBerrys.SimpleSpleef.handlers.SSArenaHandler.restoreArena(SSArenaHandler.java:479)
    at me.BlahBerrys.SimpleSpleef.handlers.SSGameHandler.endGame(SSGameHandler.java:190)
    at me.BlahBerrys.SimpleSpleef.handlers.SSGameHandler.updateGame(SSGameHandler.java:59)
    at me.BlahBerrys.SimpleSpleef.SSTimer$3.run(SSTimer.java:143)
    at org.bukkit.craftbukkit.v1_5_R3.scheduler.CraftTask.run(CraftTask.java:53)
    at org.bukkit.craftbukkit.v1_5_R3.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:345)
    at net.minecraft.server.v1_5_R3.MinecraftServer.r(MinecraftServer.java:513)
    at net.minecraft.server.v1_5_R3.DedicatedServer.r(DedicatedServer.java:226)
    at net.minecraft.server.v1_5_R3.MinecraftServer.q(MinecraftServer.java:477)
    at net.minecraft.server.v1_5_R3.MinecraftServer.run(MinecraftServer.java:410)
    at net.minecraft.server.v1_5_R3.ThreadServerApplication.run(SourceFile:573)
    


    Meh code:

    Code:java
    1.  
    2. WorldEditPlugin wep = (WorldEditPlugin) Bukkit.getServer().getPluginManager().getPlugin("WorldEdit");
    3. if (wep == null) {
    4. return;
    5. }
    6.  
    7. TerrainManager tm = new TerrainManager(wep, player);
    8. File saveFile = new File(SSMain.getInstance().getDataFolder(), arenaName);
    9.  
    10. try {
    11. tm.saveTerrain(saveFile, pointA, pointB);
    12. } catch (FilenameException e) {
    13. player.sendMessage("Error: 1");
    14. return;
    15. } catch (DataException e) {
    16. player.sendMessage("Error: 2");
    17. return;
    18. } catch (IOException e) {
    19. player.sendMessage("Error: 3");
    20. return;
    21. }
    22.  
    23.  
    24.  
    25. WorldEditPlugin wep = (WorldEditPlugin) Bukkit.getServer().getPluginManager().getPlugin("WorldEdit");
    26. if (wep == null) {
    27. return;
    28. }
    29.  
    30. TerrainManager tm = new TerrainManager(wep, player);
    31. File saveFile = new File(SSMain.getInstance().getDataFolder(), arenaName);
    32.  
    33. try {
    34. tm.loadSchematic(saveFile);
    35. } catch (FilenameException e) {
    36. player.sendMessage("Error: 1");
    37. return;
    38. } catch (DataException e) {
    39. player.sendMessage("Error: 2");
    40. return;
    41. } catch (IOException e) {
    42. player.sendMessage("Error: 3");
    43. return;
    44. } catch (MaxChangedBlocksException e) {
    45. player.sendMessage("Error: 4");
    46. return;
    47. } catch (EmptyClipboardException e) {
    48. player.sendMessage("Error: 5");
    49. return;
    50. }
    51.  
     
  13. Offline

    desht

    Yes, it still works. Looks to me like you're passing a null player object.
     
  14. Offline

    Ultimate_n00b

    This still works incredibly well, but I noticed it pastes it from the North-West corner.
    Is there anyway to change this?
     
  15. Offline

    chasechocolate

    Ultimate_n00b this uses the WorldEdit API to paste it at a given location, so unless you want to create your own paste method, no.
     
  16. I Am Trying To Use This and have it working, but it causes 5 seconds of lag on the server to load the schem, and it is a minigames server, so i cannot have that
    anyways to stop the amount of lag it is causing?
     
  17. Offline

    Onlineids

    This is a year old......
     
  18. Offline

    L33m4n123

    And? Just because its one year old does not mean that it should not be allowed to touch. He is asking something related to the topic. The Topic Creator is still active on Bukkit. So why not?


    I am not using this class but I'd guess the reason you have the 5 seconds of lag is, that the schematic is too big to be pasted for your server as all that stuff is done sync with the mainthread. So an Idea would be splitting up that schematic into like 10 smaller ones and paste them one after another. [If your players are not directly where you paste the stuff]
     
    Esophose and Garris0n like this.

  19. Good Idea, I Will Look Into It, I Hope This Helps
     
  20. Offline

    Giraffeknee

    I tried using this with new builds of WorldEdit and it is giving me errors. Some of the stuff has been deprecated that is used in the TerrainManager class. I really love this and want it to work so bad!

    Yeah whenever I instantiate TerrainManager (TerrainManager tm = new TerrainManager(getWorldEdit(), world);), and trust me I check if the world or worldedit are null (and they're not), it freaks out.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 26, 2016
  21. Offline

    desht

    I've tested with WorldEdit 5.6.2 and my ChessCraft plugin, and it works fine.

    Update 1: And with the latest WorldEdit-5.7-SNAPSHOT from sk89's Maven repo - also working fine.

    Update 2: Also compiled with 5.7-SNAPSHOT as a build dependency - again no errors, no deprecation warnings, works fine.

    Update 3: Ran with 6.0.0-SNAPSHOT - hey, it works fine :)

    Update 4: So 6.0.0 deprecates LocalPlayer. However, it still compiles and runs fine against WE 6.0.0. I'll look at getting it updated though, time to learn the WE 6 API, I guess.

    Sorry to say, but if it's "freaking out" (which as error reports go, ranks down there with "it doesn't work"), then I would guess you're doing something wrong.
     
  22. Offline

    Giraffeknee

    Alright, I'll try it again and give you the full error if it doesn't work.
     
  23. Offline

    dsouzamatt

    desht I can't thank you enough for creating this! You've made coding my minigame a whole lot easier. :)
     
    desht likes this.
Thread Status:
Not open for further replies.

Share This Page