Improved Schematic Class
Improved the Schematic class. Added support for reading schematic files. That functionality still needs to be integrated and tested. Made minor changes to WorldOperation and its derived classes. Also fixed a few bugs in Schematic's export functions that were found during testing. The exporting code still doesn't do all the changes (e.g. block standardization) that had been implemented before.
This commit is contained in:
parent
210c791af4
commit
77efb63a5f
5 changed files with 212 additions and 36 deletions
|
@ -18,7 +18,7 @@ public class CompactBoundsOperation extends WorldOperation
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean start(World world, int x, int y, int z, int width, int height, int length)
|
||||
protected boolean initialize(World world, int x, int y, int z, int width, int height, int length)
|
||||
{
|
||||
minX = Integer.MAX_VALUE;
|
||||
minY = Integer.MAX_VALUE;
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package StevenDimDoors.mod_pocketDim.schematic;
|
||||
|
||||
public class InvalidSchematicException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -1011044077455149932L;
|
||||
|
||||
public InvalidSchematicException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public InvalidSchematicException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidSchematicException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,23 @@
|
|||
package StevenDimDoors.mod_pocketDim.schematic;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import net.minecraft.nbt.CompressedStreamTools;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
import StevenDimDoors.mod_pocketDim.Point3D;
|
||||
|
||||
/**
|
||||
* Represents an MC schematic and provides functions for loading, storing, and manipulating schematics.
|
||||
* This functionality has no dependencies to Dimensional Doors.
|
||||
*/
|
||||
public class Schematic {
|
||||
|
||||
protected short width;
|
||||
|
@ -57,9 +65,115 @@ public class Schematic {
|
|||
return (NBTTagList) tileEntities.copy();
|
||||
}
|
||||
|
||||
public static Schematic readFromFile()
|
||||
public static Schematic readFromFile(String schematicPath) throws FileNotFoundException, InvalidSchematicException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return readFromFile(new File(schematicPath));
|
||||
}
|
||||
|
||||
public static Schematic readFromFile(File schematicFile) throws FileNotFoundException, InvalidSchematicException
|
||||
{
|
||||
return readFromStream(new FileInputStream(schematicFile));
|
||||
}
|
||||
|
||||
public static Schematic readFromResource(String resourcePath) throws InvalidSchematicException
|
||||
{
|
||||
//We need an instance of a class in the mod to retrieve a resource
|
||||
Schematic empty = new Schematic((short) 0, (short) 0, (short) 0, null, null, null);
|
||||
InputStream schematicStream = empty.getClass().getResourceAsStream(resourcePath);
|
||||
return readFromStream(schematicStream);
|
||||
}
|
||||
|
||||
private static Schematic readFromStream(InputStream schematicStream) throws InvalidSchematicException
|
||||
{
|
||||
short width;
|
||||
short height;
|
||||
short length;
|
||||
int volume;
|
||||
int pairs;
|
||||
|
||||
byte[] metadata = null; //block metadata
|
||||
byte[] lowBits = null; //first 8 bits of the block IDs
|
||||
byte[] highBits = null; //additional 4 bits of the block IDs
|
||||
short[] blocks = null; //list of combined block IDs
|
||||
NBTTagList tileEntities = null; //storage for tile entities in NBT form
|
||||
NBTTagCompound schematicTag; //the NBT data extracted from the schematic file
|
||||
boolean hasExtendedBlockIDs; //indicates whether the schematic contains extended block IDs
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
schematicTag = CompressedStreamTools.readCompressed(schematicStream);
|
||||
schematicStream.close(); //readCompressed() probably closes the stream anyway, but close again to be sure.
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidSchematicException("The schematic could not be decoded.");
|
||||
}
|
||||
|
||||
//load size of schematic to generate
|
||||
width = schematicTag.getShort("Width");
|
||||
height = schematicTag.getShort("Height");
|
||||
length = schematicTag.getShort("Length");
|
||||
volume = width * length * height;
|
||||
|
||||
if (width < 0)
|
||||
throw new InvalidSchematicException("The schematic cannot have a negative width.");
|
||||
if (height < 0)
|
||||
throw new InvalidSchematicException("The schematic cannot have a negative height.");
|
||||
if (length < 0)
|
||||
throw new InvalidSchematicException("The schematic cannot have a negative length.");
|
||||
|
||||
//load block info
|
||||
lowBits = schematicTag.getByteArray("Blocks");
|
||||
highBits = schematicTag.getByteArray("AddBlocks");
|
||||
metadata = schematicTag.getByteArray("Data");
|
||||
hasExtendedBlockIDs = (highBits.length != 0);
|
||||
|
||||
if (volume != lowBits.length)
|
||||
throw new InvalidSchematicException("The schematic has data for fewer blocks than its dimensions indicate.");
|
||||
if (volume != metadata.length)
|
||||
throw new InvalidSchematicException("The schematic has metadata for fewer blocks than its dimensions indicate.");
|
||||
if (volume > 2 * highBits.length && highBits.length != 0)
|
||||
throw new InvalidSchematicException("The schematic has extended block IDs for fewer blocks than its dimensions indicate.");
|
||||
|
||||
blocks = new short[volume];
|
||||
if (hasExtendedBlockIDs)
|
||||
{
|
||||
//Combine the split block IDs into a single value
|
||||
pairs = volume - (volume & 1);
|
||||
int index;
|
||||
for (index = 0; index < pairs; index += 2)
|
||||
{
|
||||
blocks[index] = (short) (((highBits[index >> 1] & 0x0F) << 8) + lowBits[index]);
|
||||
blocks[index + 1] = (short) (((highBits[index >> 1] & 0xF0) << 4) + lowBits[index + 1]);
|
||||
}
|
||||
if (index < volume)
|
||||
{
|
||||
blocks[index] = lowBits[index >> 1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Copy the blockIDs
|
||||
for (int index = 0; index < volume; index++)
|
||||
blocks[index] = lowBits[index];
|
||||
}
|
||||
|
||||
//Get the list of tile entities
|
||||
tileEntities = schematicTag.getTagList("TileEntities");
|
||||
|
||||
return new Schematic(width, height, length, blocks, metadata, tileEntities);
|
||||
}
|
||||
catch (InvalidSchematicException ex)
|
||||
{
|
||||
//Throw the exception again to pass it to the caller.
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidSchematicException("An unexpected error occurred while trying to decode the schematic.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static Schematic copyFromWorld(World world, int x, int y, int z, short width, short height, short length, boolean doCompactBounds)
|
||||
|
@ -118,6 +232,10 @@ public class Schematic {
|
|||
highBits[index >> 1] = (byte) ((blocks[index] >> 8) & 0x0F);
|
||||
hasHighBits |= (highBits[index >> 1] != 0);
|
||||
}
|
||||
for (index = 0; index < blocks.length; index++)
|
||||
{
|
||||
lowBits[index] = (byte) (blocks[index] & 0xFF);
|
||||
}
|
||||
return hasHighBits;
|
||||
}
|
||||
|
||||
|
@ -140,16 +258,16 @@ public class Schematic {
|
|||
schematicTag.setTag("Entities", new NBTTagList());
|
||||
schematicTag.setString("Materials", "Alpha");
|
||||
|
||||
byte[] lowBytes = new byte[blocks.length];
|
||||
byte[] highBytes = new byte[(blocks.length >> 1) + 1];
|
||||
boolean hasExtendedIDs = encodeBlockIDs(blocks, lowBytes, highBytes);
|
||||
byte[] lowBits = new byte[blocks.length];
|
||||
byte[] highBits = new byte[(blocks.length >> 1) + 1];
|
||||
boolean hasExtendedIDs = encodeBlockIDs(blocks, lowBits, highBits);
|
||||
|
||||
schematicTag.setByteArray("Blocks", lowBytes);
|
||||
schematicTag.setByteArray("Blocks", lowBits);
|
||||
schematicTag.setByteArray("Data", metadata);
|
||||
|
||||
if (hasExtendedIDs)
|
||||
{
|
||||
schematicTag.setByteArray("AddBlocks", highBytes);
|
||||
schematicTag.setByteArray("AddBlocks", highBits);
|
||||
}
|
||||
|
||||
if (copyTileEntities)
|
||||
|
@ -180,4 +298,40 @@ public class Schematic {
|
|||
//Closing twice will not throw an exception.
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
public void copyToWorld(World world, int x, int y, int z)
|
||||
{
|
||||
int index;
|
||||
int count;
|
||||
int dx, dy, dz;
|
||||
|
||||
//Copy blocks and metadata into the world
|
||||
index = 0;
|
||||
for (dy = 0; dy < height; dy++)
|
||||
{
|
||||
for (dz = 0; dz < length; dz++)
|
||||
{
|
||||
for (dx = 0; dx < width; dx++)
|
||||
{
|
||||
world.setBlock(x + dx, y + dy, z + dz, blocks[index], metadata[index], 3);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Copy tile entities into the world
|
||||
count = tileEntities.tagCount();
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
NBTTagCompound tileTag = (NBTTagCompound) tileEntities.tagAt(index);
|
||||
//Rewrite its location to be in world coordinates
|
||||
dx = tileTag.getInteger("x") + x;
|
||||
dy = tileTag.getInteger("y") + y;
|
||||
dz = tileTag.getInteger("z") + z;
|
||||
tileTag.setInteger("x", dx);
|
||||
tileTag.setInteger("y", dy);
|
||||
tileTag.setInteger("z", dz);
|
||||
//Load the tile entity and put it in the world
|
||||
world.setBlockTileEntity(dx, dy, dz, TileEntity.createAndLoadEntity(tileTag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@ public class WorldCopyOperation extends WorldOperation
|
|||
super("WorldCopyOperation");
|
||||
blockIDs = null;
|
||||
metadata = null;
|
||||
tileEntities = new NBTTagList();
|
||||
tileEntities = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean start(World world, int x, int y, int z, int width, int height, int length)
|
||||
protected boolean initialize(World world, int x, int y, int z, int width, int height, int length)
|
||||
{
|
||||
index = 0;
|
||||
originX = x;
|
||||
|
@ -32,6 +32,7 @@ public class WorldCopyOperation extends WorldOperation
|
|||
originZ = z;
|
||||
blockIDs = new short[width * height * length];
|
||||
metadata = new byte[width * height * length];
|
||||
tileEntities = new NBTTagList();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ public abstract class WorldOperation {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
protected boolean start(World world, int x, int y, int z, int width, int height, int length)
|
||||
protected boolean initialize(World world, int x, int y, int z, int width, int height, int length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ public abstract class WorldOperation {
|
|||
|
||||
public boolean apply(World world, int x, int y, int z, int width, int height, int length)
|
||||
{
|
||||
if (!start(world, x, y, z, width, height, length))
|
||||
if (!initialize(world, x, y, z, width, height, length))
|
||||
return false;
|
||||
|
||||
int cx, cy, cz;
|
||||
|
|
Loading…
Reference in a new issue