Added better saving and loading methods to Schematics
Added some extra NBT utils Added support for TileEntities and Entities to schematics
This commit is contained in:
parent
8a2c30fa84
commit
7a0eea7aa0
@ -19,7 +19,27 @@
|
||||
|
||||
package com.java.sk89q.jnbt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.minecraft.server.v1_8_R3.NBTBase;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagByte;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagByteArray;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagDouble;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagEnd;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagFloat;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagInt;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagIntArray;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagList;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagLong;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagShort;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagString;
|
||||
|
||||
/**
|
||||
* A class which contains NBT-related utility methods.
|
||||
@ -166,5 +186,207 @@ public final class NBTUtils {
|
||||
}
|
||||
return expected.cast(tag);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static NBTBase toNative(Tag tag) {
|
||||
if (tag instanceof IntArrayTag) {
|
||||
return toNative((IntArrayTag) tag);
|
||||
|
||||
} else if (tag instanceof ListTag) {
|
||||
return toNative((ListTag) tag);
|
||||
|
||||
} else if (tag instanceof LongTag) {
|
||||
return toNative((LongTag) tag);
|
||||
|
||||
} else if (tag instanceof StringTag) {
|
||||
return toNative((StringTag) tag);
|
||||
|
||||
} else if (tag instanceof IntTag) {
|
||||
return toNative((IntTag) tag);
|
||||
|
||||
} else if (tag instanceof ByteTag) {
|
||||
return toNative((ByteTag) tag);
|
||||
|
||||
} else if (tag instanceof ByteArrayTag) {
|
||||
return toNative((ByteArrayTag) tag);
|
||||
|
||||
} else if (tag instanceof CompoundTag) {
|
||||
return toNative((CompoundTag) tag);
|
||||
|
||||
} else if (tag instanceof FloatTag) {
|
||||
return toNative((FloatTag) tag);
|
||||
|
||||
} else if (tag instanceof ShortTag) {
|
||||
return toNative((ShortTag) tag);
|
||||
|
||||
} else if (tag instanceof DoubleTag) {
|
||||
return toNative((DoubleTag) tag);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can't convert tag of type " + tag.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
||||
public static NBTTagIntArray toNative(IntArrayTag tag) {
|
||||
int[] value = tag.getValue();
|
||||
return new NBTTagIntArray(Arrays.copyOf(value, value.length));
|
||||
}
|
||||
|
||||
public static NBTTagList toNative(ListTag tag) {
|
||||
NBTTagList list = new NBTTagList();
|
||||
for (Tag child : tag.getValue()) {
|
||||
if (child instanceof EndTag) {
|
||||
continue;
|
||||
}
|
||||
list.add(toNative(child));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static NBTTagLong toNative(LongTag tag) {
|
||||
return new NBTTagLong(tag.getValue());
|
||||
}
|
||||
|
||||
public static NBTTagString toNative(StringTag tag) {
|
||||
return new NBTTagString(tag.getValue());
|
||||
}
|
||||
|
||||
public static NBTTagInt toNative(IntTag tag) {
|
||||
return new NBTTagInt(tag.getValue());
|
||||
}
|
||||
|
||||
public static NBTTagByte toNative(ByteTag tag) {
|
||||
return new NBTTagByte(tag.getValue());
|
||||
}
|
||||
|
||||
public static NBTTagByteArray toNative(ByteArrayTag tag) {
|
||||
byte[] value = tag.getValue();
|
||||
return new NBTTagByteArray(Arrays.copyOf(value, value.length));
|
||||
}
|
||||
|
||||
public static NBTTagCompound toNative(CompoundTag tag) {
|
||||
NBTTagCompound compound = new NBTTagCompound();
|
||||
for (Entry<String, Tag> child : tag.getValue().entrySet()) {
|
||||
compound.set(child.getKey(), toNative(child.getValue()));
|
||||
}
|
||||
return compound;
|
||||
}
|
||||
|
||||
public static NBTTagFloat toNative(FloatTag tag) {
|
||||
return new NBTTagFloat(tag.getValue());
|
||||
}
|
||||
|
||||
public static NBTTagShort toNative(ShortTag tag) {
|
||||
return new NBTTagShort(tag.getValue());
|
||||
}
|
||||
|
||||
public static NBTTagDouble toNative(DoubleTag tag) {
|
||||
return new NBTTagDouble(tag.getValue());
|
||||
}
|
||||
|
||||
public static Tag fromNative(NBTBase other) {
|
||||
if (other instanceof NBTTagIntArray) {
|
||||
return fromNative((NBTTagIntArray) other);
|
||||
|
||||
} else if (other instanceof NBTTagList) {
|
||||
return fromNative((NBTTagList) other);
|
||||
|
||||
} else if (other instanceof NBTTagEnd) {
|
||||
return fromNative((NBTTagEnd) other);
|
||||
|
||||
} else if (other instanceof NBTTagLong) {
|
||||
return fromNative((NBTTagLong) other);
|
||||
|
||||
} else if (other instanceof NBTTagString) {
|
||||
return fromNative((NBTTagString) other);
|
||||
|
||||
} else if (other instanceof NBTTagInt) {
|
||||
return fromNative((NBTTagInt) other);
|
||||
|
||||
} else if (other instanceof NBTTagByte) {
|
||||
return fromNative((NBTTagByte) other);
|
||||
|
||||
} else if (other instanceof NBTTagByteArray) {
|
||||
return fromNative((NBTTagByteArray) other);
|
||||
|
||||
} else if (other instanceof NBTTagCompound) {
|
||||
return fromNative((NBTTagCompound) other);
|
||||
|
||||
} else if (other instanceof NBTTagFloat) {
|
||||
return fromNative((NBTTagFloat) other);
|
||||
|
||||
} else if (other instanceof NBTTagShort) {
|
||||
return fromNative((NBTTagShort) other);
|
||||
|
||||
} else if (other instanceof NBTTagDouble) {
|
||||
return fromNative((NBTTagDouble) other);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can't convert other of type " + other.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
||||
public static IntArrayTag fromNative(NBTTagIntArray other) {
|
||||
int[] value = other.c();
|
||||
return new IntArrayTag(Arrays.copyOf(value, value.length));
|
||||
}
|
||||
|
||||
public static ListTag fromNative(NBTTagList other) {
|
||||
other = (NBTTagList) other.clone();
|
||||
List<Tag> list = new ArrayList<Tag>();
|
||||
Class<? extends Tag> listClass = StringTag.class;
|
||||
for (int i = 0; i < other.size(); i++) {
|
||||
Tag child = fromNative(other.a(0));
|
||||
list.add(child);
|
||||
listClass = child.getClass();
|
||||
}
|
||||
return new ListTag(listClass, list);
|
||||
}
|
||||
|
||||
public static EndTag fromNative(NBTTagEnd other) {
|
||||
return new EndTag();
|
||||
}
|
||||
|
||||
public static LongTag fromNative(NBTTagLong other) {
|
||||
return new LongTag(other.c());
|
||||
}
|
||||
|
||||
public static StringTag fromNative(NBTTagString other) {
|
||||
return new StringTag(other.a_());
|
||||
}
|
||||
|
||||
public static IntTag fromNative(NBTTagInt other) {
|
||||
return new IntTag(other.d());
|
||||
}
|
||||
|
||||
public static ByteTag fromNative(NBTTagByte other) {
|
||||
return new ByteTag(other.f());
|
||||
}
|
||||
|
||||
public static ByteArrayTag fromNative(NBTTagByteArray other) {
|
||||
byte[] value = other.c();
|
||||
return new ByteArrayTag(Arrays.copyOf(value, value.length));
|
||||
}
|
||||
|
||||
public static CompoundTag fromNative(NBTTagCompound other) {
|
||||
@SuppressWarnings("unchecked") Collection<String> tags = other.c();
|
||||
Map<String, Tag> map = new HashMap<String, Tag>();
|
||||
for (String tagName : tags) {
|
||||
map.put(tagName, fromNative(other.get(tagName)));
|
||||
}
|
||||
return new CompoundTag(map);
|
||||
}
|
||||
|
||||
public static FloatTag fromNative(NBTTagFloat other) {
|
||||
return new FloatTag(other.h());
|
||||
}
|
||||
|
||||
public static ShortTag fromNative(NBTTagShort other) {
|
||||
return new ShortTag(other.e());
|
||||
}
|
||||
|
||||
public static DoubleTag fromNative(NBTTagDouble other) {
|
||||
return new DoubleTag(other.g());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,29 @@
|
||||
package mineplex.core.common.block.schematic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
|
||||
import org.bukkit.util.BlockVector;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import com.mysql.jdbc.Util;
|
||||
import com.java.sk89q.jnbt.CompoundTag;
|
||||
import com.java.sk89q.jnbt.NBTUtils;
|
||||
import com.java.sk89q.jnbt.Tag;
|
||||
|
||||
import mineplex.core.common.block.DataLocationMap;
|
||||
import mineplex.core.common.util.MapUtil;
|
||||
import mineplex.core.common.util.UtilBlock;
|
||||
import net.minecraft.server.v1_8_R3.Entity;
|
||||
import net.minecraft.server.v1_8_R3.EntityTypes;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_8_R3.TileEntity;
|
||||
import net.minecraft.server.v1_8_R3.WorldServer;
|
||||
|
||||
public class Schematic
|
||||
{
|
||||
@ -18,8 +33,11 @@ public class Schematic
|
||||
private final short[] _blocks;
|
||||
private final byte[] _blockData;
|
||||
private final Vector _weOffset;
|
||||
|
||||
public Schematic(short width, short height, short length, short[] blocks, byte[] blockData, Vector worldEditOffset)
|
||||
private final Map<BlockVector, Map<String, Tag>> _tileEntities;
|
||||
private final List<Tag> _entities;
|
||||
|
||||
|
||||
public Schematic(short width, short height, short length, short[] blocks, byte[] blockData, Vector worldEditOffset, Map<BlockVector, Map<String, Tag>> tileEntities, List<Tag> entities)
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
@ -27,6 +45,18 @@ public class Schematic
|
||||
_blocks = blocks;
|
||||
_blockData = blockData;
|
||||
_weOffset = worldEditOffset;
|
||||
_tileEntities = tileEntities;
|
||||
_entities = entities;
|
||||
}
|
||||
|
||||
public Schematic(short width, short height, short length, short[] blocks, byte[] blockData, Vector worldEditOffset, Map<BlockVector, Map<String, Tag>> tileEntities)
|
||||
{
|
||||
this(width, height, length, blocks, blockData, worldEditOffset, tileEntities, new ArrayList<>());
|
||||
}
|
||||
|
||||
public Schematic(short width, short height, short length, short[] blocks, byte[] blockData, Vector worldEditOffset)
|
||||
{
|
||||
this(width, height, length, blocks, blockData, worldEditOffset, new HashMap<>());
|
||||
}
|
||||
|
||||
public Schematic(short width, short height, short length, short[] blocks, byte[] blockData)
|
||||
@ -34,29 +64,33 @@ public class Schematic
|
||||
this(width, height, length, blocks, blockData, null);
|
||||
}
|
||||
|
||||
public DataLocationMap paste(Location originLocation)
|
||||
public SchematicData paste(Location originLocation)
|
||||
{
|
||||
return paste(originLocation, false);
|
||||
}
|
||||
|
||||
public DataLocationMap paste(Location originLocation, boolean ignoreAir)
|
||||
public SchematicData paste(Location originLocation, boolean ignoreAir)
|
||||
{
|
||||
return paste(originLocation, ignoreAir, false);
|
||||
}
|
||||
|
||||
public DataLocationMap paste(Location originLocation, boolean ignoreAir, boolean worldEditOffset)
|
||||
public SchematicData paste(Location originLocation, boolean ignoreAir, boolean worldEditOffset)
|
||||
{
|
||||
if(worldEditOffset && hasWorldEditOffset())
|
||||
{
|
||||
originLocation = originLocation.clone().add(_weOffset);
|
||||
}
|
||||
DataLocationMap locationMap = new DataLocationMap();
|
||||
|
||||
SchematicData output = new SchematicData(locationMap, originLocation.getWorld());
|
||||
|
||||
int startX = originLocation.getBlockX();
|
||||
int startY = originLocation.getBlockY();
|
||||
int startZ = originLocation.getBlockZ();
|
||||
|
||||
UtilBlock.startQuickRecording();
|
||||
|
||||
WorldServer nmsWorld = ((CraftWorld)originLocation.getWorld()).getHandle();
|
||||
|
||||
for (int x = 0; x < _width; x++)
|
||||
{
|
||||
@ -106,16 +140,44 @@ public class Schematic
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UtilBlock.setQuick(originLocation.getWorld(), startX + x, startY + y, startZ + z, materialId, _blockData[index]);
|
||||
|
||||
BlockVector bv = new BlockVector(x,y,z);
|
||||
|
||||
output.getBlocksRaw().add(bv);
|
||||
|
||||
Map<String, Tag> map = _tileEntities.get(bv);
|
||||
if(map != null)
|
||||
{
|
||||
TileEntity te = nmsWorld.getTileEntity(MapUtil.getBlockPos(bv));
|
||||
if(te == null) continue;
|
||||
CompoundTag weTag = new CompoundTag(map);
|
||||
NBTTagCompound tag = NBTUtils.toNative(weTag);
|
||||
te.a(tag);
|
||||
|
||||
output.getTileEntitiesRaw().add(bv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UtilBlock.stopQuickRecording();
|
||||
|
||||
for(Tag tag : _entities)
|
||||
{
|
||||
if(tag instanceof CompoundTag)
|
||||
{
|
||||
CompoundTag ctag = (CompoundTag) tag;
|
||||
NBTTagCompound nmsTag = NBTUtils.toNative(ctag);
|
||||
Entity nmsEntity = EntityTypes.a(nmsTag, nmsWorld);
|
||||
if(nmsEntity == null) continue;
|
||||
|
||||
output.getEntitiesRaw().add(nmsEntity.getBukkitEntity());
|
||||
}
|
||||
}
|
||||
|
||||
return locationMap;
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -174,6 +236,13 @@ public class Schematic
|
||||
{
|
||||
return _weOffset != null;
|
||||
}
|
||||
|
||||
public Vector getWorldEditOffset()
|
||||
{
|
||||
if(!hasWorldEditOffset()) return null;
|
||||
|
||||
return _weOffset.clone();
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
@ -224,6 +293,16 @@ public class Schematic
|
||||
{
|
||||
return _blockData;
|
||||
}
|
||||
|
||||
public List<Tag> getEntities()
|
||||
{
|
||||
return _entities;
|
||||
}
|
||||
|
||||
public Map<BlockVector, Map<String, Tag>> getTileEntities()
|
||||
{
|
||||
return _tileEntities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
|
@ -1,27 +1,63 @@
|
||||
package mineplex.core.common.block.schematic;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.util.BlockVector;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import com.java.sk89q.jnbt.ByteArrayTag;
|
||||
import com.java.sk89q.jnbt.CompoundTag;
|
||||
import com.java.sk89q.jnbt.IntTag;
|
||||
import com.java.sk89q.jnbt.ListTag;
|
||||
import com.java.sk89q.jnbt.NBTInputStream;
|
||||
import com.java.sk89q.jnbt.NBTOutputStream;
|
||||
import com.java.sk89q.jnbt.NBTUtils;
|
||||
import com.java.sk89q.jnbt.NamedTag;
|
||||
import com.java.sk89q.jnbt.ShortTag;
|
||||
import com.java.sk89q.jnbt.StringTag;
|
||||
import com.java.sk89q.jnbt.Tag;
|
||||
|
||||
import net.minecraft.server.v1_8_R3.BlockPosition;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_8_R3.TileEntity;
|
||||
import net.minecraft.server.v1_8_R3.WorldServer;
|
||||
|
||||
public class UtilSchematic
|
||||
{
|
||||
|
||||
public static Schematic loadSchematic(File file) throws IOException
|
||||
{
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(fis));
|
||||
return loadSchematic(fis);
|
||||
}
|
||||
|
||||
public static Schematic loadSchematic(byte[] bytes) throws IOException
|
||||
{
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
|
||||
return loadSchematic(bis);
|
||||
}
|
||||
|
||||
public static Schematic loadSchematic(InputStream input) throws IOException
|
||||
{
|
||||
NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(input));
|
||||
|
||||
NamedTag rootTag = nbtStream.readNamedTag();
|
||||
nbtStream.close();
|
||||
@ -35,9 +71,11 @@ public class UtilSchematic
|
||||
short width = getChildTag(schematic, "Width", ShortTag.class).getValue();
|
||||
short height = getChildTag(schematic, "Height", ShortTag.class).getValue();
|
||||
short length = getChildTag(schematic, "Length", ShortTag.class).getValue();
|
||||
|
||||
|
||||
byte[] blockId = getChildTag(schematic, "Blocks", ByteArrayTag.class).getValue();
|
||||
byte[] addId = new byte[0];
|
||||
short[] blocks = new short[blockId.length];
|
||||
short[] blocks = new short[blockId.length]; // Have to later combine IDs
|
||||
byte[] blockData = getChildTag(schematic, "Data", ByteArrayTag.class).getValue();
|
||||
|
||||
Vector weOffset = null;
|
||||
@ -49,11 +87,14 @@ public class UtilSchematic
|
||||
weOffset = new Vector(x, y, z);
|
||||
}
|
||||
|
||||
// We support 4096 block IDs using the same method as vanilla Minecraft, where
|
||||
// the highest 4 bits are stored in a separate byte array.
|
||||
if (schematic.containsKey("AddBlocks"))
|
||||
{
|
||||
addId = getChildTag(schematic, "AddBlocks", ByteArrayTag.class).getValue();
|
||||
}
|
||||
|
||||
// Combine the AddBlocks data with the first 8-bit block ID
|
||||
for (int index = 0; index < blockId.length; index++)
|
||||
{
|
||||
if ((index >> 1) >= addId.length)
|
||||
@ -66,9 +107,233 @@ public class UtilSchematic
|
||||
blocks[index] = (short) (((addId[index >> 1] & 0xF0) << 4) + (blockId[index] & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
// Need to pull out tile entities
|
||||
List<Tag> tileEntities = getChildTag(schematic, "TileEntities", ListTag.class).getValue();
|
||||
Map<BlockVector, Map<String, Tag>> tileEntitiesMap = new HashMap<>();
|
||||
|
||||
for (Tag tag : tileEntities)
|
||||
{
|
||||
if (!(tag instanceof CompoundTag)) {
|
||||
continue;
|
||||
}
|
||||
CompoundTag t = (CompoundTag) tag;
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int z = 0;
|
||||
|
||||
Map<String, Tag> values = new HashMap<>();
|
||||
|
||||
for (Map.Entry<String, Tag> entry : t.getValue().entrySet())
|
||||
{
|
||||
if (entry.getValue() instanceof IntTag)
|
||||
{
|
||||
if (entry.getKey().equals("x"))
|
||||
{
|
||||
x = ((IntTag) entry.getValue()).getValue();
|
||||
} else if (entry.getKey().equals("y"))
|
||||
{
|
||||
y = ((IntTag) entry.getValue()).getValue();
|
||||
} else if (entry.getKey().equals("z"))
|
||||
{
|
||||
z = ((IntTag) entry.getValue()).getValue();
|
||||
}
|
||||
}
|
||||
|
||||
values.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
BlockVector vec = new BlockVector(x, y, z);
|
||||
tileEntitiesMap.put(vec, values);
|
||||
}
|
||||
|
||||
List<Tag> entityTags = getChildTag(schematic, "Entities", ListTag.class).getValue();
|
||||
|
||||
|
||||
return new Schematic(width, height, length, blocks, blockData, weOffset);
|
||||
return new Schematic(width, height, length, blocks, blockData, weOffset, tileEntitiesMap, entityTags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param schematic The schematic you want to turn into bytes
|
||||
* @return Returns a byte array of the schematic which may be used for saving the schematic to DB or file
|
||||
*/
|
||||
public static byte[] getBytes(Schematic schematic)
|
||||
{
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
writeBytes(schematic, output);
|
||||
return output.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param schematic The scheamtic you want save somewhere
|
||||
* @return Writes out this schematic on byte form
|
||||
*/
|
||||
public static void writeBytes(Schematic schematic, OutputStream output)
|
||||
{
|
||||
Map<String, Tag> map = new HashMap<>();
|
||||
|
||||
short width = schematic.getWidth();
|
||||
short height = schematic.getHeight();
|
||||
short length = schematic.getLength();
|
||||
|
||||
map.put("Width", new ShortTag(width));
|
||||
map.put("Height", new ShortTag(height));
|
||||
map.put("Length", new ShortTag(length));
|
||||
|
||||
if(schematic.hasWorldEditOffset())
|
||||
{
|
||||
Vector weOffset = schematic.getWorldEditOffset();
|
||||
map.put("WEOffsetX", new IntTag(weOffset.getBlockX()));
|
||||
map.put("WEOffsetY", new IntTag(weOffset.getBlockX()));
|
||||
map.put("WEOffsetZ", new IntTag(weOffset.getBlockX()));
|
||||
}
|
||||
|
||||
map.put("Materials", new StringTag("Alpha"));
|
||||
|
||||
short[] sblocks = schematic.getBlocks();
|
||||
Map<BlockVector, Map<String, Tag>> stileEntities = schematic.getTileEntities();
|
||||
|
||||
|
||||
byte[] blocks = new byte[sblocks.length];
|
||||
byte[] addBlocks = null;
|
||||
byte[] blockData = schematic.getBlockData();
|
||||
List<Tag> tileEntities = new ArrayList<Tag>();
|
||||
|
||||
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;
|
||||
BlockVector bv = new BlockVector(x, y, z);
|
||||
|
||||
//Save 4096 IDs in an AddBlocks section
|
||||
if(sblocks[index] > 255)
|
||||
{
|
||||
if (addBlocks == null) { // Lazily create section
|
||||
addBlocks = new byte[(blocks.length >> 1) + 1];
|
||||
}
|
||||
|
||||
addBlocks[index >> 1] = (byte) (((index & 1) == 0) ?
|
||||
addBlocks[index >> 1] & 0xF0 | (sblocks[index] >> 8) & 0xF
|
||||
: addBlocks[index >> 1] & 0xF | ((sblocks[index] >> 8) & 0xF) << 4);
|
||||
}
|
||||
|
||||
blocks[index] = (byte) sblocks[index];
|
||||
|
||||
Map<String, Tag> values = stileEntities.get(bv);
|
||||
if(values != null)
|
||||
{
|
||||
values.put("x", new IntTag(x));
|
||||
values.put("y", new IntTag(y));
|
||||
values.put("z", new IntTag(z));
|
||||
|
||||
CompoundTag tileEntityTag = new CompoundTag(values);
|
||||
tileEntities.add(tileEntityTag);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map.put("Blocks", new ByteArrayTag(blocks));
|
||||
map.put("Data", new ByteArrayTag(blockData));
|
||||
map.put("TileEntities", new ListTag(CompoundTag.class, tileEntities));
|
||||
|
||||
if (addBlocks != null) {
|
||||
map.put("AddBlocks", new ByteArrayTag(addBlocks));
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// Entities
|
||||
// ====================================================================
|
||||
|
||||
List<Tag> entities = schematic.getEntities();
|
||||
|
||||
map.put("Entities", new ListTag(CompoundTag.class, entities));
|
||||
|
||||
// ====================================================================
|
||||
// Output
|
||||
// ====================================================================
|
||||
|
||||
CompoundTag schematicTag = new CompoundTag(map);
|
||||
|
||||
try (NBTOutputStream outputStream = new NBTOutputStream(new GZIPOutputStream(output)))
|
||||
{
|
||||
outputStream.writeNamedTag("Schematic", schematicTag);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static Schematic createSchematic(Location locA, Location locB)
|
||||
{
|
||||
return createSchematic(locA, locB, null);
|
||||
}
|
||||
|
||||
public static Schematic createSchematic(Location locA, Location locB, Vector worldEditOffset)
|
||||
{
|
||||
World world = locA.getWorld();
|
||||
|
||||
Vector min = Vector.getMinimum(locA.toVector(), locB.toVector());
|
||||
Vector max = Vector.getMaximum(locB.toVector(), locA.toVector());
|
||||
|
||||
short width = (short) (max.getBlockX()-min.getBlockX());
|
||||
short height = (short) (max.getBlockY()-min.getBlockY());
|
||||
short length = (short) (max.getBlockZ()-min.getBlockZ());
|
||||
|
||||
short[] blocks = new short[width*height*length];
|
||||
byte[] blocksData = new byte[blocks.length];
|
||||
|
||||
WorldServer nmsWorld = ((CraftWorld)world).getHandle();
|
||||
|
||||
Map<BlockVector, Map<String, Tag>> tileEntities = new HashMap<>();
|
||||
|
||||
for(int x = min.getBlockX(); x < max.getBlockX(); x++)
|
||||
{
|
||||
for(int y = min.getBlockY(); y < max.getBlockY(); y++)
|
||||
{
|
||||
for(int z = min.getBlockZ(); z < max.getBlockZ(); z++)
|
||||
{
|
||||
Block b = world.getBlockAt(x, y, z);
|
||||
|
||||
int index = y * width * length + z * width + x;
|
||||
|
||||
blocks[index] = (short) b.getTypeId();
|
||||
blocksData[index] = b.getData();
|
||||
|
||||
BlockPosition bp = new BlockPosition(x, y, z);
|
||||
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(bp);
|
||||
if(tileEntity == null) continue;
|
||||
|
||||
NBTTagCompound nmsTag = new NBTTagCompound();
|
||||
tileEntity.b(nmsTag);
|
||||
|
||||
CompoundTag tag = NBTUtils.fromNative(nmsTag);
|
||||
tileEntities.put(new BlockVector(x, y, z), tag.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Tag> entities = new ArrayList<>();
|
||||
for(Entity e : world.getEntities())
|
||||
{
|
||||
if(e.getLocation().toVector().isInAABB(min, max))
|
||||
{
|
||||
net.minecraft.server.v1_8_R3.Entity nmsEntity = ((CraftEntity)e).getHandle();
|
||||
NBTTagCompound nmsTag = new NBTTagCompound();
|
||||
nmsEntity.c(nmsTag);
|
||||
CompoundTag tag = NBTUtils.fromNative(nmsTag);
|
||||
entities.add(tag);
|
||||
}
|
||||
}
|
||||
|
||||
return new Schematic(width, height, length, blocks, blocksData, worldEditOffset, tileEntities, entities);
|
||||
}
|
||||
|
||||
|
||||
|
@ -19,6 +19,7 @@ import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import net.minecraft.server.v1_8_R3.Block;
|
||||
import net.minecraft.server.v1_8_R3.BlockPosition;
|
||||
@ -284,6 +285,16 @@ public class MapUtil
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static BlockPosition getBlockPos(Location loc)
|
||||
{
|
||||
return getBlockPos(loc.toVector());
|
||||
}
|
||||
|
||||
public static BlockPosition getBlockPos(Vector v)
|
||||
{
|
||||
return getBlockPos(v.getBlockX(), v.getBlockY(), v.getBlockZ());
|
||||
}
|
||||
|
||||
public static BlockPosition getBlockPos(int x, int y, int z)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user