package com.intellectualcrafters.plot; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.plugin.java.JavaPlugin; import com.intellectualcrafters.jnbt.*; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.Map; import java.util.zip.GZIPInputStream; /** * Created by Citymonstret on 2014-09-15. */ public class SchematicHandler { public static boolean paste(Location location, Schematic schematic, Plot plot) { if (schematic == null) { PlotMain.sendConsoleSenderMessage("Schematic == null :|"); return false; } try { Dimension demensions = schematic.getSchematicDimension(); int WIDTH = demensions.getX(); int LENGTH = demensions.getZ(); int HEIGHT = demensions.getY(); DataCollection[] blocks = schematic.getBlockCollection(); Location l1 = PlotHelper.getPlotBottomLoc(plot.getWorld(), plot.getId()); int sy = location.getWorld().getHighestBlockYAt(l1.getBlockX()+1, l1.getBlockZ()+1); l1 = l1.add(1, sy-1, 1); World world = location.getWorld(); for (int x = 0; x < WIDTH; x++) { for (int z = 0; z < LENGTH; z++) { for (int y = 0; y < HEIGHT; y++) { int index = y * WIDTH * LENGTH + z * WIDTH + x; short id = blocks[index].getBlock(); byte data = blocks[index].getData(); Block block = world.getBlockAt(l1.getBlockX()+x, l1.getBlockY()+y, l1.getBlockZ()+z); PlotBlock plotblock = new PlotBlock(id, data); PlotHelper.setBlock(block, plotblock); } } } } catch (Exception e) { return false; } return true; } public static Schematic getSchematic(String name) { { File parent = new File(JavaPlugin.getPlugin(PlotMain.class).getDataFolder() + File.separator + "schematics"); if (!parent.exists()) { parent.mkdir(); } } File file = new File(JavaPlugin.getPlugin(PlotMain.class).getDataFolder() + File.separator + "schematics" + File.separator + name + ".schematic"); if (!file.exists()) { PlotMain.sendConsoleSenderMessage(file.toString() + " doesn't exist"); return null; } Schematic schematic = null; try { InputStream iStream = new FileInputStream(file); NBTInputStream stream = new NBTInputStream(new GZIPInputStream(iStream)); CompoundTag tag = (CompoundTag) stream.readTag(); stream.close(); Map tagMap = tag.getValue(); byte[] addId = new byte[0]; if (tagMap.containsKey("AddBlocks")) { addId = ByteArrayTag.class.cast(tagMap.get("AddBlocks")).getValue(); } short width = ShortTag.class.cast(tagMap.get("Width")).getValue(); short length = ShortTag.class.cast(tagMap.get("Length")).getValue(); short height = ShortTag.class.cast(tagMap.get("Height")).getValue(); byte[] b = ByteArrayTag.class.cast(tagMap.get("Blocks")).getValue(); byte[] d = ByteArrayTag.class.cast(tagMap.get("Data")).getValue(); short[] blocks = new short[b.length]; Dimension dimension = new Dimension(width, height, length); for (int index = 0; index < b.length; index++) { if ((index >> 1) >= addId.length) { // No corresponding // AddBlocks index blocks[index] = (short) (b[index] & 0xFF); } else { if ((index & 1) == 0) { blocks[index] = (short) (((addId[index >> 1] & 0x0F) << 8) + (b[index] & 0xFF)); } else { blocks[index] = (short) (((addId[index >> 1] & 0xF0) << 4) + (b[index] & 0xFF)); } } } DataCollection[] collection = new DataCollection[b.length]; for (int x = 0; x < b.length; x++) { collection[x] = new DataCollection(blocks[x], d[x]); } schematic = new Schematic(collection, dimension, file); } catch (Exception e) { e.printStackTrace(); return null; } return schematic; } public static class Schematic { private DataCollection[] blockCollection; private Dimension schematicDimension; private File file; public Schematic(DataCollection[] blockCollection, Dimension schematicDimension, File file) { this.blockCollection = blockCollection; this.schematicDimension = schematicDimension; this.file = file; } public File getFile() { return this.file; } public Dimension getSchematicDimension() { return this.schematicDimension; } public DataCollection[] getBlockCollection() { return this.blockCollection; } } public static class Dimension { private int x; private int y; private int z; public Dimension(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } public int getX() { return this.x; } public int getY() { return this.y; } public int getZ() { return this.z; } } /** * Saves a schematic to a file path * @param tag * @param path * @return */ public static boolean save(CompoundTag tag, String path) { if (tag==null) { PlotMain.sendConsoleSenderMessage("&cCannot save empty tag"); return false; } try { OutputStream stream = new FileOutputStream(path); NBTOutputStream output = new NBTOutputStream(stream); output.writeTag(tag); output.close(); stream.close(); } catch (IOException e) { e.printStackTrace(); return false; } return true; } /** * Gets the schematic of a plot * @param world * @param plot * @return */ public static CompoundTag getCompoundTag(World world, PlotId id) { if (!PlotMain.getPlots(world).containsKey(id)) { return null; // Plot is empty } // loading chunks final Location pos1 = PlotHelper.getPlotBottomLoc(world, id).add(1, 0, 1); final Location pos2 = PlotHelper.getPlotTopLoc(world, id); for (int i = (pos1.getBlockX() / 16) * 16; i < (16 + ((pos2.getBlockX() / 16) * 16)); i += 16) { for (int j = (pos1.getBlockZ() / 16) * 16; j < (16 + ((pos2.getBlockZ() / 16) * 16)); j += 16) { Chunk chunk = world.getChunkAt(i, j); boolean result = chunk.load(false); if (!result) { // Plot is not even generated return null; } } } int width = pos2.getBlockX()-pos1.getBlockX(); int height = 256; int length = pos2.getBlockZ()-pos1.getBlockZ(); HashMap schematic = new HashMap(); schematic.put("Width", new ShortTag("Width", (short) width)); schematic.put("Length", new ShortTag("Length", (short) length)); schematic.put("Height", new ShortTag("Height", (short) height)); schematic.put("Materials", new StringTag("Materials", "Alpha")); schematic.put("WEOriginX", new IntTag("WEOriginX", 0)); schematic.put("WEOriginY", new IntTag("WEOriginY", 0)); schematic.put("WEOriginZ", new IntTag("WEOriginZ", 0)); schematic.put("WEOffsetX", new IntTag("WEOffsetX", 0)); schematic.put("WEOffsetY", new IntTag("WEOffsetY", 0)); schematic.put("WEOffsetZ", new IntTag("WEOffsetZ", 0)); byte[] blocks = new byte[width * height * length]; byte[] addBlocks = null; byte[] blockData = new byte[width * height * length]; for (int x = 0; x < width; x++) { for (int z = 0; z < length; z++) { for (int y = 0; y < height; y++) { int index = y * width * length + z * width + x; Block block = world.getBlockAt(new Location(world, pos1.getBlockX() + x, 0 + y, pos1.getBlockZ() + z)); int id2 = block.getTypeId(); if (id2 > 255) { if (addBlocks == null) { addBlocks = new byte[(blocks.length >> 1) + 1]; } addBlocks[index >> 1] = (byte) (((index & 1) == 0) ? addBlocks[index >> 1] & 0xF0 | (id2 >> 8) & 0xF : addBlocks[index >> 1] & 0xF | ((id2 >> 8) & 0xF) << 4); } blocks[index] = (byte) id2; blockData[index] = (byte) block.getData(); // We need worldedit to save tileentity data or entities // - it uses NMS and CB internal code, which changes every update } } } schematic.put("Blocks", new ByteArrayTag("Blocks", blocks)); schematic.put("Data", new ByteArrayTag("Data", blockData)); if (addBlocks != null) { schematic.put("AddBlocks", new ByteArrayTag("AddBlocks", addBlocks)); } CompoundTag schematicTag = new CompoundTag("Schematic", schematic); return schematicTag; } public static class DataCollection { private short block; private byte data; public DataCollection(short block, byte data) { this.block = block; this.data = data; } public short getBlock() { return this.block; } public byte getData() { return this.data; } } }