Created DungeonSchematic Class
Created DungeonSchematic, a class that extends Schematic and adds DD-specific functionality such as methods for filtering the schematic's block before importing and exporting. Testing confirms that DungeonSchematic works well so far, although it still lacks critical features. Made some minor changes to Schematic and copied SchematicLoader.setBlockDirectly(). I realized during testing that setting blocks without using that function could cause problems. First, it's possible that the blocks would not be placed if chunks weren't created. Second, there are issues with blocks updating if we use World to set them, even if block updates are disabled. That causes some torches to break and other weird problems. Added classes to support block filtering operations applied to Schematic. These are used to implement ID standardization and removing mod blocks when importing.
This commit is contained in:
58
StevenDimDoors/mod_pocketDim/schematic/CompoundFilter.java
Normal file
58
StevenDimDoors/mod_pocketDim/schematic/CompoundFilter.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package StevenDimDoors.mod_pocketDim.schematic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CompoundFilter extends SchematicFilter {
|
||||
|
||||
private ArrayList<SchematicFilter> filters;
|
||||
|
||||
public CompoundFilter()
|
||||
{
|
||||
super("CompoundFilter");
|
||||
filters = new ArrayList<SchematicFilter>();
|
||||
}
|
||||
|
||||
public void addFilter(SchematicFilter filter)
|
||||
{
|
||||
filters.add(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean initialize(Schematic schematic, short[] blocks, byte[] metadata)
|
||||
{
|
||||
for (SchematicFilter filter : filters)
|
||||
{
|
||||
if (!filter.initialize(schematic, blocks, metadata))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !filters.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean finish()
|
||||
{
|
||||
for (SchematicFilter filter : filters)
|
||||
{
|
||||
if (!filter.finish())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean applyToBlock(int index, short[] blocks, byte[] metadata)
|
||||
{
|
||||
for (SchematicFilter filter : filters)
|
||||
{
|
||||
if (!filter.applyToBlock(index, blocks, metadata))
|
||||
{
|
||||
return !filter.terminates();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package StevenDimDoors.mod_pocketDim.schematic;
|
||||
|
||||
public class ReplacementFilter extends SchematicFilter {
|
||||
|
||||
private short targetBlock;
|
||||
private byte targetMetadata;
|
||||
private boolean matchMetadata;
|
||||
private short replacementBlock;
|
||||
private byte replacementMetadata;
|
||||
private boolean changeMetadata;
|
||||
|
||||
public ReplacementFilter(short targetBlock, byte targetMetadata, short replacementBlock, byte replacementMetadata)
|
||||
{
|
||||
super("ReplacementFilter");
|
||||
this.targetBlock = targetBlock;
|
||||
this.targetMetadata = targetMetadata;
|
||||
this.matchMetadata = true;
|
||||
this.replacementBlock = replacementBlock;
|
||||
this.replacementMetadata = replacementMetadata;
|
||||
this.changeMetadata = true;
|
||||
}
|
||||
|
||||
public ReplacementFilter(short targetBlock, short replacementBlock, byte replacementMetadata)
|
||||
{
|
||||
super("ReplacementFilter");
|
||||
this.targetBlock = targetBlock;
|
||||
this.matchMetadata = false;
|
||||
this.replacementBlock = replacementBlock;
|
||||
this.replacementMetadata = replacementMetadata;
|
||||
this.changeMetadata = true;
|
||||
}
|
||||
|
||||
public ReplacementFilter(short targetBlock, byte targetMetadata, short replacementBlock)
|
||||
{
|
||||
super("ReplacementFilter");
|
||||
this.targetBlock = targetBlock;
|
||||
this.targetMetadata = targetMetadata;
|
||||
this.matchMetadata = true;
|
||||
this.replacementBlock = replacementBlock;
|
||||
this.changeMetadata = false;
|
||||
}
|
||||
|
||||
public ReplacementFilter(short targetBlock, short replacementBlock)
|
||||
{
|
||||
super("ReplacementFilter");
|
||||
this.targetBlock = targetBlock;
|
||||
this.matchMetadata = false;
|
||||
this.replacementBlock = replacementBlock;
|
||||
this.changeMetadata = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean applyToBlock(int index, short[] blocks, byte[] metadata)
|
||||
{
|
||||
if (blocks[index] == targetBlock)
|
||||
{
|
||||
if ((matchMetadata && metadata[index] == targetMetadata) || !matchMetadata)
|
||||
{
|
||||
blocks[index] = replacementBlock;
|
||||
if (changeMetadata)
|
||||
{
|
||||
metadata[index] = replacementMetadata;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean terminates()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,14 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
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 net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
import StevenDimDoors.mod_pocketDim.Point3D;
|
||||
|
||||
/**
|
||||
@@ -26,7 +29,7 @@ public class Schematic {
|
||||
|
||||
protected short[] blocks;
|
||||
protected byte[] metadata;
|
||||
protected NBTTagList tileEntities = new NBTTagList();
|
||||
protected NBTTagList tileEntities;
|
||||
|
||||
protected Schematic(short width, short height, short length, short[] blocks, byte[] metadata, NBTTagList tileEntities)
|
||||
{
|
||||
@@ -37,8 +40,20 @@ public class Schematic {
|
||||
this.metadata = metadata;
|
||||
this.tileEntities = tileEntities;
|
||||
}
|
||||
|
||||
protected Schematic(Schematic source)
|
||||
{
|
||||
//Shallow copy constructor - critical for code reuse in derived classes since
|
||||
//source's fields will be inaccessible if the derived class is in another package.
|
||||
this.width = source.width;
|
||||
this.height = source.height;
|
||||
this.length = source.length;
|
||||
this.blocks = source.blocks;
|
||||
this.metadata = source.metadata;
|
||||
this.tileEntities = source.tileEntities;
|
||||
}
|
||||
|
||||
private int calculateIndex(int x, int y, int z)
|
||||
protected int calculateIndex(int x, int y, int z)
|
||||
{
|
||||
if (x < 0 || x >= width)
|
||||
throw new IndexOutOfBoundsException("x must be non-negative and less than width");
|
||||
@@ -83,7 +98,7 @@ public class Schematic {
|
||||
return readFromStream(schematicStream);
|
||||
}
|
||||
|
||||
private static Schematic readFromStream(InputStream schematicStream) throws InvalidSchematicException
|
||||
public static Schematic readFromStream(InputStream schematicStream) throws InvalidSchematicException
|
||||
{
|
||||
short width;
|
||||
short height;
|
||||
@@ -165,7 +180,8 @@ public class Schematic {
|
||||
//Get the list of tile entities
|
||||
tileEntities = schematicTag.getTagList("TileEntities");
|
||||
|
||||
return new Schematic(width, height, length, blocks, metadata, tileEntities);
|
||||
Schematic result = new Schematic(width, height, length, blocks, metadata, tileEntities);
|
||||
return result;
|
||||
}
|
||||
catch (InvalidSchematicException ex)
|
||||
{
|
||||
@@ -246,7 +262,13 @@ public class Schematic {
|
||||
return writeToNBT(true);
|
||||
}
|
||||
|
||||
private NBTTagCompound writeToNBT(boolean copyTileEntities)
|
||||
protected NBTTagCompound writeToNBT(boolean copyTileEntities)
|
||||
{
|
||||
return writeToNBT(width, height, length, blocks, metadata, tileEntities, copyTileEntities);
|
||||
}
|
||||
|
||||
protected static NBTTagCompound writeToNBT(short width, short height, short length, short[] blocks, byte[] metadata,
|
||||
NBTTagList tileEntities, boolean copyTileEntities)
|
||||
{
|
||||
//This is the main storage function. Schematics are really compressed NBT tags, so if we can generate
|
||||
//the tags, most of the work is done. All the other storage functions will rely on this one.
|
||||
@@ -301,6 +323,11 @@ public class Schematic {
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
public boolean applyFilter(SchematicFilter filter)
|
||||
{
|
||||
return filter.apply(this, this.blocks, this.metadata);
|
||||
}
|
||||
|
||||
public void copyToWorld(World world, int x, int y, int z)
|
||||
{
|
||||
//This isn't implemented as a WorldOperation because it doesn't quite fit the structure of those operations.
|
||||
@@ -317,8 +344,8 @@ public class Schematic {
|
||||
{
|
||||
for (dx = 0; dx < width; dx++)
|
||||
{
|
||||
//Don't cause block updates!
|
||||
world.setBlock(x + dx, y + dy, z + dz, blocks[index], metadata[index], 2);
|
||||
//In the future, we might want to make this more efficient by building whole chunks at a time
|
||||
setBlockDirectly(world, x + dx, y + dy, z + dz, blocks[index], metadata[index]);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
@@ -339,4 +366,38 @@ public class Schematic {
|
||||
world.setBlockTileEntity(dx, dy, dz, TileEntity.createAndLoadEntity(tileTag));
|
||||
}
|
||||
}
|
||||
|
||||
protected static void setBlockDirectly(World world, int x, int y, int z, int blockID, int metadata)
|
||||
{
|
||||
if (blockID != 0 && Block.blocksList[blockID] == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int cX = x >> 4;
|
||||
int cZ = z >> 4;
|
||||
int cY = y >> 4;
|
||||
Chunk chunk;
|
||||
|
||||
int localX = (x % 16) < 0 ? (x % 16) + 16 : (x % 16);
|
||||
int localZ = (z % 16) < 0 ? (z % 16) + 16 : (z % 16);
|
||||
ExtendedBlockStorage extBlockStorage;
|
||||
|
||||
try
|
||||
{
|
||||
chunk = world.getChunkFromChunkCoords(cX, cZ);
|
||||
extBlockStorage = chunk.getBlockStorageArray()[cY];
|
||||
if (extBlockStorage == null)
|
||||
{
|
||||
extBlockStorage = new ExtendedBlockStorage(cY << 4, !world.provider.hasNoSky);
|
||||
chunk.getBlockStorageArray()[cY] = extBlockStorage;
|
||||
}
|
||||
extBlockStorage.setExtBlockID(localX, y & 15, localZ, blockID);
|
||||
extBlockStorage.setExtBlockMetadata(localX, y & 15, localZ, metadata);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
55
StevenDimDoors/mod_pocketDim/schematic/SchematicFilter.java
Normal file
55
StevenDimDoors/mod_pocketDim/schematic/SchematicFilter.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package StevenDimDoors.mod_pocketDim.schematic;
|
||||
|
||||
public class SchematicFilter {
|
||||
|
||||
private String name;
|
||||
|
||||
protected SchematicFilter(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean apply(Schematic schematic, short[] blocks, byte[] metadata)
|
||||
{
|
||||
if (!initialize(schematic, blocks, metadata))
|
||||
return false;
|
||||
|
||||
for (int index = 0; index < blocks.length; index++)
|
||||
{
|
||||
if (!applyToBlock(index, blocks, metadata) && terminates())
|
||||
return false;
|
||||
}
|
||||
|
||||
return finish();
|
||||
}
|
||||
|
||||
protected boolean initialize(Schematic schematic, short[] blocks, byte[] metadata)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean applyToBlock(int index, short[] blocks, byte[] metadata)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean finish()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean terminates()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user