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;
|
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;
|
||||||
|
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.
|
* A class which contains NBT-related utility methods.
|
||||||
@ -167,4 +187,206 @@ public final class NBTUtils {
|
|||||||
return expected.cast(tag);
|
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;
|
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.DyeColor;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
|
||||||
|
import org.bukkit.util.BlockVector;
|
||||||
import org.bukkit.util.Vector;
|
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.block.DataLocationMap;
|
||||||
|
import mineplex.core.common.util.MapUtil;
|
||||||
import mineplex.core.common.util.UtilBlock;
|
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
|
public class Schematic
|
||||||
{
|
{
|
||||||
@ -18,8 +33,11 @@ public class Schematic
|
|||||||
private final short[] _blocks;
|
private final short[] _blocks;
|
||||||
private final byte[] _blockData;
|
private final byte[] _blockData;
|
||||||
private final Vector _weOffset;
|
private final Vector _weOffset;
|
||||||
|
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)
|
|
||||||
|
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;
|
_width = width;
|
||||||
_height = height;
|
_height = height;
|
||||||
@ -27,6 +45,18 @@ public class Schematic
|
|||||||
_blocks = blocks;
|
_blocks = blocks;
|
||||||
_blockData = blockData;
|
_blockData = blockData;
|
||||||
_weOffset = worldEditOffset;
|
_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)
|
public Schematic(short width, short height, short length, short[] blocks, byte[] blockData)
|
||||||
@ -34,17 +64,17 @@ public class Schematic
|
|||||||
this(width, height, length, blocks, blockData, null);
|
this(width, height, length, blocks, blockData, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataLocationMap paste(Location originLocation)
|
public SchematicData paste(Location originLocation)
|
||||||
{
|
{
|
||||||
return paste(originLocation, false);
|
return paste(originLocation, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataLocationMap paste(Location originLocation, boolean ignoreAir)
|
public SchematicData paste(Location originLocation, boolean ignoreAir)
|
||||||
{
|
{
|
||||||
return paste(originLocation, ignoreAir, false);
|
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())
|
if(worldEditOffset && hasWorldEditOffset())
|
||||||
{
|
{
|
||||||
@ -52,12 +82,16 @@ public class Schematic
|
|||||||
}
|
}
|
||||||
DataLocationMap locationMap = new DataLocationMap();
|
DataLocationMap locationMap = new DataLocationMap();
|
||||||
|
|
||||||
|
SchematicData output = new SchematicData(locationMap, originLocation.getWorld());
|
||||||
|
|
||||||
int startX = originLocation.getBlockX();
|
int startX = originLocation.getBlockX();
|
||||||
int startY = originLocation.getBlockY();
|
int startY = originLocation.getBlockY();
|
||||||
int startZ = originLocation.getBlockZ();
|
int startZ = originLocation.getBlockZ();
|
||||||
|
|
||||||
UtilBlock.startQuickRecording();
|
UtilBlock.startQuickRecording();
|
||||||
|
|
||||||
|
WorldServer nmsWorld = ((CraftWorld)originLocation.getWorld()).getHandle();
|
||||||
|
|
||||||
for (int x = 0; x < _width; x++)
|
for (int x = 0; x < _width; x++)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < _height; y++)
|
for (int y = 0; y < _height; y++)
|
||||||
@ -107,15 +141,43 @@ public class Schematic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UtilBlock.setQuick(originLocation.getWorld(), startX + x, startY + y, startZ + z, materialId, _blockData[index]);
|
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();
|
UtilBlock.stopQuickRecording();
|
||||||
|
|
||||||
return locationMap;
|
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 output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -175,6 +237,13 @@ public class Schematic
|
|||||||
return _weOffset != null;
|
return _weOffset != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector getWorldEditOffset()
|
||||||
|
{
|
||||||
|
if(!hasWorldEditOffset()) return null;
|
||||||
|
|
||||||
|
return _weOffset.clone();
|
||||||
|
}
|
||||||
|
|
||||||
public int getSize()
|
public int getSize()
|
||||||
{
|
{
|
||||||
return _blocks.length;
|
return _blocks.length;
|
||||||
@ -225,6 +294,16 @@ public class Schematic
|
|||||||
return _blockData;
|
return _blockData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Tag> getEntities()
|
||||||
|
{
|
||||||
|
return _entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<BlockVector, Map<String, Tag>> getTileEntities()
|
||||||
|
{
|
||||||
|
return _tileEntities;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
|
@ -1,27 +1,63 @@
|
|||||||
package mineplex.core.common.block.schematic;
|
package mineplex.core.common.block.schematic;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
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.Map;
|
||||||
import java.util.zip.GZIPInputStream;
|
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 org.bukkit.util.Vector;
|
||||||
|
|
||||||
import com.java.sk89q.jnbt.ByteArrayTag;
|
import com.java.sk89q.jnbt.ByteArrayTag;
|
||||||
import com.java.sk89q.jnbt.CompoundTag;
|
import com.java.sk89q.jnbt.CompoundTag;
|
||||||
import com.java.sk89q.jnbt.IntTag;
|
import com.java.sk89q.jnbt.IntTag;
|
||||||
|
import com.java.sk89q.jnbt.ListTag;
|
||||||
import com.java.sk89q.jnbt.NBTInputStream;
|
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.NamedTag;
|
||||||
import com.java.sk89q.jnbt.ShortTag;
|
import com.java.sk89q.jnbt.ShortTag;
|
||||||
|
import com.java.sk89q.jnbt.StringTag;
|
||||||
import com.java.sk89q.jnbt.Tag;
|
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 class UtilSchematic
|
||||||
{
|
{
|
||||||
|
|
||||||
public static Schematic loadSchematic(File file) throws IOException
|
public static Schematic loadSchematic(File file) throws IOException
|
||||||
{
|
{
|
||||||
FileInputStream fis = new FileInputStream(file);
|
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();
|
NamedTag rootTag = nbtStream.readNamedTag();
|
||||||
nbtStream.close();
|
nbtStream.close();
|
||||||
@ -35,9 +71,11 @@ public class UtilSchematic
|
|||||||
short width = getChildTag(schematic, "Width", ShortTag.class).getValue();
|
short width = getChildTag(schematic, "Width", ShortTag.class).getValue();
|
||||||
short height = getChildTag(schematic, "Height", ShortTag.class).getValue();
|
short height = getChildTag(schematic, "Height", ShortTag.class).getValue();
|
||||||
short length = getChildTag(schematic, "Length", ShortTag.class).getValue();
|
short length = getChildTag(schematic, "Length", ShortTag.class).getValue();
|
||||||
|
|
||||||
|
|
||||||
byte[] blockId = getChildTag(schematic, "Blocks", ByteArrayTag.class).getValue();
|
byte[] blockId = getChildTag(schematic, "Blocks", ByteArrayTag.class).getValue();
|
||||||
byte[] addId = new byte[0];
|
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();
|
byte[] blockData = getChildTag(schematic, "Data", ByteArrayTag.class).getValue();
|
||||||
|
|
||||||
Vector weOffset = null;
|
Vector weOffset = null;
|
||||||
@ -49,11 +87,14 @@ public class UtilSchematic
|
|||||||
weOffset = new Vector(x, y, z);
|
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"))
|
if (schematic.containsKey("AddBlocks"))
|
||||||
{
|
{
|
||||||
addId = getChildTag(schematic, "AddBlocks", ByteArrayTag.class).getValue();
|
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++)
|
for (int index = 0; index < blockId.length; index++)
|
||||||
{
|
{
|
||||||
if ((index >> 1) >= addId.length)
|
if ((index >> 1) >= addId.length)
|
||||||
@ -67,8 +108,232 @@ public class UtilSchematic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Need to pull out tile entities
|
||||||
|
List<Tag> tileEntities = getChildTag(schematic, "TileEntities", ListTag.class).getValue();
|
||||||
|
Map<BlockVector, Map<String, Tag>> tileEntitiesMap = new HashMap<>();
|
||||||
|
|
||||||
return new Schematic(width, height, length, blocks, blockData, weOffset);
|
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, 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.entity.Player;
|
||||||
import org.bukkit.event.world.WorldUnloadEvent;
|
import org.bukkit.event.world.WorldUnloadEvent;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
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.Block;
|
||||||
import net.minecraft.server.v1_8_R3.BlockPosition;
|
import net.minecraft.server.v1_8_R3.BlockPosition;
|
||||||
@ -285,6 +286,16 @@ public class MapUtil
|
|||||||
return true;
|
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)
|
public static BlockPosition getBlockPos(int x, int y, int z)
|
||||||
{
|
{
|
||||||
return new BlockPosition(x, y, z);
|
return new BlockPosition(x, y, z);
|
||||||
|
Loading…
Reference in New Issue
Block a user