Restore/Regen from Schematic

Discussion in 'Plugin Development' started by stuntguy3000, Jul 18, 2013.

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

    stuntguy3000

    Hello,

    I was wondering (with a command or something) is there a way to restore/paste in a schematic to regen a map.
     
  2. Offline

    savagesun

    I did something like this once. There is no Bukkit method or anything to do this, but it has been done.
    This is all based off of someone else's code but for the life of me I can't find it. So here's what I have. (working for the most part).
    You'll need a Schematic class:
    Code:
    public class Schematic {
        private byte[] blocks;
        private byte[] data;
        private short width;
        private short length;
        private short height;
     
        public Schematic(byte[] blocks, byte[] data, short width, short length, short height) {
            this.blocks = blocks;
            this.data = data;
            this.width = width;
            this.length = length;
            this.height = height;
        }
     
        public byte[] getBlocks() {
            return this.blocks;
        }
     
        public byte[] getData() {
            return this.data;
        }
     
        public short getWidth() {
            return this.width;
        }
     
        public short getLength() {
            return this.length;
        }
     
        public short getHeight() {
            return this.height;
        }
    }
    
    A method to load the schematic:
    Code:
    public static Schematic loadSchematic(File f) throws IOException {
            FileInputStream stream = new FileInputStream(f);
            NBTTagCompound nbtData = NBTCompressedStreamTools.a(stream);
         
            short width = nbtData.getShort("Width");
            short height = nbtData.getShort("Height");
            short length = nbtData.getShort("Length");
         
            byte[] blocks = nbtData.getByteArray("Blocks");
            byte[] data = nbtData.getByteArray("Data");
         
            return new Schematic(blocks, data, width, length, height);
        }
    And a method to past the schematic:
    Code:
    public static void pasteOldSchematic(World w, Location l, Schematic schem) {
            byte[] blocks = schem.getBlocks();
            byte[] blockData = schem.getData();
         
            short length = schem.getLength();
            short width = schem.getWidth();
            short height = schem.getHeight();
         
            for(int x = 0; x < width; ++x) {
                for(int y = 0; y < height; ++y) {
                    for(int z = 0; z < length; ++z) {
                        //int index = y * width * length + z * width + x;
                        int index = x + (y * length + z) * width;
                     
                        Block b = new Location(w, x + l.getX(), y + l.getY(), z + l.getZ()).getBlock();
                        b.setTypeIdAndData(blocks[index], blockData[index], true);
                    }
                }
            }
        }
    I'm not sure exactly what you mean by "to regen a map." But if you mean to build block by block you'll still have to use most of this, just use some kind of timed task to iterate through the schematic so a block is placed once every x seconds or so instead of all at once.

    Edit: Occasionally it throws an exception when pasting a schematic. I have no idea what causes it, since it only happens every now and then. My solution was to just ignore it by handling the exception without printing anything (so it wouldn't alarm anyone) and continuously paste the schematic until it worked (which ranged anywhere from 1-4 times). Not elegant, but no one seems to have the answer to the issue. (I think the exception is IndexOutOfBounds. You'll run into it eventually).
     
    stuntguy3000 likes this.
  3. Offline

    stuntguy3000

    Thanks!!!
     
  4. Offline

    NoLiver92

    savagesun
    I have used your code and i have found out what the error is but unfortunately not how to fix it.

    the block data is stored in hex in the schematic file, when you convert the hex to a byte if the hex value has a signed decimal (negative number) and a positive number the conversion to byte causes you to get the negative value, hence the error you get. If you convert the hex to int, you get the correct decimal value.

    known blocks to cause the error (id's): 155, 152

    this is what i have found so far there could be more. I am looking for the solution but it means editing the JNBT library
     
Thread Status:
Not open for further replies.

Share This Page