From 210c791af475104b11da9486b867b5a9f0ecc48b Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sat, 27 Jul 2013 06:52:30 -0400 Subject: [PATCH 1/7] Created Schematic Class Separated part of the dungeon-exporting logic into a new class: Schematic. Also created a few classes to implement important operations. Some parts of the original exporting logic are missing now, such as mapping certain blocks to standard IDs. That will be reimplemented in the future. Importing schematics is not supported yet. I need to test what's done so far. --- .../mod_pocketDim/helpers/DungeonHelper.java | 154 +-------------- .../schematic/CompactBoundsOperation.java | 73 +++++++ .../mod_pocketDim/schematic/Schematic.java | 183 ++++++++++++++++++ .../schematic/WorldCopyOperation.java | 75 +++++++ .../schematic/WorldOperation.java | 64 ++++++ 5 files changed, 400 insertions(+), 149 deletions(-) create mode 100644 StevenDimDoors/mod_pocketDim/schematic/CompactBoundsOperation.java create mode 100644 StevenDimDoors/mod_pocketDim/schematic/Schematic.java create mode 100644 StevenDimDoors/mod_pocketDim/schematic/WorldCopyOperation.java create mode 100644 StevenDimDoors/mod_pocketDim/schematic/WorldOperation.java diff --git a/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 268fbd2..f9cfa8d 100644 --- a/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -1,7 +1,6 @@ package StevenDimDoors.mod_pocketDim.helpers; import java.io.File; -import java.io.FileOutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -11,10 +10,6 @@ import java.util.Random; import java.util.regex.Pattern; 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.util.WeightedRandom; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.DDProperties; @@ -23,6 +18,7 @@ import StevenDimDoors.mod_pocketDim.DungeonGenerator; import StevenDimDoors.mod_pocketDim.LinkData; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.items.itemDimDoor; +import StevenDimDoors.mod_pocketDim.schematic.Schematic; import StevenDimDoors.mod_pocketDim.util.WeightedContainer; public class DungeonHelper @@ -383,153 +379,13 @@ public class DungeonHelper public boolean exportDungeon(World world, int centerX, int centerY, int centerZ, String exportPath) { - int xMin, yMin, zMin; - int xMax, yMax, zMax; - int xStart, yStart, zStart; - int xEnd, yEnd, zEnd; - - //Find the smallest bounding box that contains all non-air blocks within a max radius around the player. - xMax = yMax = zMax = Integer.MIN_VALUE; - xMin = yMin = zMin = Integer.MAX_VALUE; - - xStart = centerX - MAX_EXPORT_RADIUS; - zStart = centerZ - MAX_EXPORT_RADIUS; - yStart = Math.max(centerY - MAX_EXPORT_RADIUS, 0); - - xEnd = centerX + MAX_EXPORT_RADIUS; - zEnd = centerZ + MAX_EXPORT_RADIUS; - yEnd = Math.min(centerY + MAX_EXPORT_RADIUS, world.getHeight()); - - //This could be done more efficiently, but honestly, this is the simplest approach and it - //makes it easy for us to verify that the code is correct. - for (int y = yStart; y <= yEnd; y++) - { - for (int z = zStart; z <= zEnd; z++) - { - for (int x = xStart; x <= xEnd; x++) - { - if (!world.isAirBlock(x, y, z)) - { - xMax = x > xMax ? x : xMax; - zMax = z > zMax ? z : zMax; - yMax = y > yMax ? y : yMax; - - xMin = x < xMin ? x : xMin; - zMin = z < zMin ? z : zMin; - yMin = y < yMin ? y : yMin; - } - } - } - } - - //Export all the blocks within our selected bounding box - short width = (short) (xMax - xMin + 1); - short height = (short) (yMax - yMin + 1); - short length = (short) (zMax - zMin + 1); - - byte[] blocks = new byte[width * height * length]; - byte[] addBlocks = null; - byte[] blockData = new byte[width * height * length]; - NBTTagList tileEntities = new NBTTagList(); - - for (int y = 0; y < height; y++) - { - for (int z = 0; z < length; z++) - { - for (int x = 0; x < width; x++) - { - int index = y * width * length + z * width + x; - int blockID = world.getBlockId(x + xMin, y + yMin, z + zMin); - int metadata = world.getBlockMetadata(x + xMin, y + yMin, z + zMin); - boolean changed = false; - - if (blockID == properties.DimensionalDoorID) - { - blockID = Block.doorIron.blockID; - changed = true; - } - if (blockID == properties.WarpDoorID) - { - blockID = Block.doorWood.blockID; - changed = true; - } - //Map fabric of reality and permafabric blocks to standard export IDs - if (blockID == properties.FabricBlockID) - { - blockID = FABRIC_OF_REALITY_EXPORT_ID; - changed = true; - } - if (blockID == properties.PermaFabricBlockID) - { - blockID = PERMAFABRIC_EXPORT_ID; - changed = true; - } - - // Save 4096 IDs in an AddBlocks section - if (blockID > 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 | (blockID >> 8) & 0xF - : addBlocks[index >> 1] & 0xF | ((blockID >> 8) & 0xF) << 4); - } - - blocks[index] = (byte) blockID; - blockData[index] = (byte) metadata; - - //Obtain and export the tile entity of the current block, if any. - //Do not obtain a tile entity if the block was changed from its original ID. - //I'm not sure if this approach is the most efficient but it works. ~SenseiKiwi - TileEntity tileEntity = !changed ? world.getBlockTileEntity(x + xMin, y + yMin, z + zMin) : null; - - if (tileEntity != null) - { - //Get the tile entity's description as a compound NBT tag - NBTTagCompound entityData = new NBTTagCompound(); - tileEntity.writeToNBT(entityData); - //Change the tile entity's location to the schematic coordinate system - entityData.setInteger("x", x); - entityData.setInteger("y", y); - entityData.setInteger("z", z); - - tileEntities.appendTag(entityData); - } - } - } - } - - //Write NBT tags for schematic file - NBTTagCompound schematicTag = new NBTTagCompound("Schematic"); - - schematicTag.setShort("Width", width); - schematicTag.setShort("Length", length); - schematicTag.setShort("Height", height); - - schematicTag.setByteArray("Blocks", blocks); - schematicTag.setByteArray("Data", blockData); - - schematicTag.setTag("Entities", new NBTTagList()); - schematicTag.setTag("TileEntities", tileEntities); - schematicTag.setString("Materials", "Alpha"); - - if (addBlocks != null) - { - schematicTag.setByteArray("AddBlocks", addBlocks); - } - //Write schematic data to a file try { - FileOutputStream outputStream = new FileOutputStream(new File(exportPath)); - CompressedStreamTools.writeCompressed(schematicTag, outputStream); - //writeCompressed() probably closes the stream on its own - call close again just in case. - //Closing twice will not throw an exception. - outputStream.close(); + short size = (short) 2 * MAX_EXPORT_RADIUS + 1; + Schematic schematic = Schematic.copyFromWorld(world, + centerX - MAX_EXPORT_RADIUS, centerY - MAX_EXPORT_RADIUS, centerZ - MAX_EXPORT_RADIUS, size, size, size, true); + schematic.writeToFile(exportPath); return true; } catch(Exception e) diff --git a/StevenDimDoors/mod_pocketDim/schematic/CompactBoundsOperation.java b/StevenDimDoors/mod_pocketDim/schematic/CompactBoundsOperation.java new file mode 100644 index 0000000..9b3ad88 --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/schematic/CompactBoundsOperation.java @@ -0,0 +1,73 @@ +package StevenDimDoors.mod_pocketDim.schematic; + +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.Point3D; + +public class CompactBoundsOperation extends WorldOperation +{ + private int minX; + private int minY; + private int minZ; + private int maxX; + private int maxY; + private int maxZ; + + public CompactBoundsOperation() + { + super("CompactBoundsOperation"); + } + + @Override + protected boolean start(World world, int x, int y, int z, int width, int height, int length) + { + minX = Integer.MAX_VALUE; + minY = Integer.MAX_VALUE; + minZ = Integer.MAX_VALUE; + maxX = x; + maxY = y; + maxZ = z; + return true; + } + + @Override + protected boolean applyToBlock(World world, int x, int y, int z) + { + //This could be done more efficiently, but honestly, this is the simplest approach and it + //makes it easy for us to verify that the code is correct. + if (!world.isAirBlock(x, y, z)) + { + maxX = x > maxX ? x : maxX; + maxZ = z > maxZ ? z : maxZ; + maxY = y > maxY ? y : maxY; + + minX = x < minX ? x : minX; + minZ = z < minZ ? z : minZ; + minY = y < minY ? y : minY; + } + return true; + } + + protected boolean finish() + { + if (minX == Integer.MAX_VALUE) + { + //The whole search space was empty! + //Compact the space to a single block. + minX = maxX; + minY = maxY; + minZ = maxZ; + return false; + } + return true; + } + + public Point3D getMaxCorner() + { + return new Point3D(maxX, maxY, maxZ); + } + + public Point3D getMinCorner() + { + return new Point3D(minX, minY, minZ); + } +} diff --git a/StevenDimDoors/mod_pocketDim/schematic/Schematic.java b/StevenDimDoors/mod_pocketDim/schematic/Schematic.java new file mode 100644 index 0000000..6e8b780 --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/schematic/Schematic.java @@ -0,0 +1,183 @@ +package StevenDimDoors.mod_pocketDim.schematic; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.Point3D; + +public class Schematic { + + protected short width; + protected short height; + protected short length; + + protected short[] blocks; + protected byte[] metadata; + protected NBTTagList tileEntities = new NBTTagList(); + + protected Schematic(short width, short height, short length, short[] blocks, byte[] metadata, NBTTagList tileEntities) + { + this.width = width; + this.height = height; + this.length = length; + this.blocks = blocks; + this.metadata = metadata; + this.tileEntities = tileEntities; + } + + private 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"); + if (y < 0 || y >= height) + throw new IndexOutOfBoundsException("y must be non-negative and less than height"); + if (z < 0 || z >= length) + throw new IndexOutOfBoundsException("z must be non-negative and less than length"); + + return (y * width * length + z * width + x); + } + + public short getBlockID(int x, int y, int z) + { + return blocks[calculateIndex(x, y, z)]; + } + + public byte getBlockMetadata(int x, int y, int z) + { + return metadata[calculateIndex(x, y, z)]; + } + + public NBTTagList getTileEntities() + { + return (NBTTagList) tileEntities.copy(); + } + + public static Schematic readFromFile() + { + throw new UnsupportedOperationException(); + } + + public static Schematic copyFromWorld(World world, int x, int y, int z, short width, short height, short length, boolean doCompactBounds) + { + if (doCompactBounds) + { + //Adjust the vertical bounds to reasonable values if necessary + int worldHeight = world.getHeight(); + int fixedY = (y < 0) ? 0 : y; + int fixedHeight = height + y - fixedY; + + if (fixedHeight + fixedY >= worldHeight) + { + fixedHeight = worldHeight - fixedY; + } + + //Compact the area to be copied to remove empty borders + CompactBoundsOperation compactor = new CompactBoundsOperation(); + compactor.apply(world, x, fixedY, z, width, fixedHeight, length); + Point3D minCorner = compactor.getMinCorner(); + Point3D maxCorner = compactor.getMaxCorner(); + + short compactWidth = (short) (maxCorner.getX() - minCorner.getX() + 1); + short compactHeight = (short) (maxCorner.getY() - minCorner.getY() + 1); + short compactLength = (short) (maxCorner.getZ() - minCorner.getZ() + 1); + + return copyFromWorld(world, minCorner.getX(), minCorner.getY(), minCorner.getZ(), + compactWidth, compactHeight, compactLength); + } + else + { + return copyFromWorld(world, x, y, z, width, height, length); + } + } + + private static Schematic copyFromWorld(World world, int x, int y, int z, short width, short height, short length) + { + //Short and sweet ^_^ + WorldCopyOperation copier = new WorldCopyOperation(); + copier.apply(world, x, y, z, width, height, length); + return new Schematic(width, height, length, copier.getBlockIDs(), copier.getMetadata(), copier.getTileEntities()); + } + + private static boolean encodeBlockIDs(short[] blocks, byte[] lowBits, byte[] highBits) + { + int index; + int length = blocks.length - (blocks.length & 1); + boolean hasHighBits = false; + for (index = 0; index < length; index += 2) + { + highBits[index >> 1] = (byte) (((blocks[index] >> 8) & 0x0F) + ((blocks[index + 1] >> 4) & 0xF0)); + hasHighBits |= (highBits[index >> 1] != 0); + } + if (index < blocks.length) + { + highBits[index >> 1] = (byte) ((blocks[index] >> 8) & 0x0F); + hasHighBits |= (highBits[index >> 1] != 0); + } + return hasHighBits; + } + + public NBTTagCompound writeToNBT() + { + return writeToNBT(true); + } + + private NBTTagCompound writeToNBT(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. + + NBTTagCompound schematicTag = new NBTTagCompound("Schematic"); + + schematicTag.setShort("Width", width); + schematicTag.setShort("Length", length); + schematicTag.setShort("Height", height); + + 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); + + schematicTag.setByteArray("Blocks", lowBytes); + schematicTag.setByteArray("Data", metadata); + + if (hasExtendedIDs) + { + schematicTag.setByteArray("AddBlocks", highBytes); + } + + if (copyTileEntities) + { + //Used when the result of this function will be passed outside this class. + //Avoids exposing the private field to external modifications. + schematicTag.setTag("TileEntities", (NBTTagList) tileEntities.copy()); + } + else + { + //Used when the result of this function is for internal use. + //It's more efficient not to copy the tags unless it's needed. + schematicTag.setTag("TileEntities", tileEntities); + } + return schematicTag; + } + + public void writeToFile(String schematicPath) throws IOException + { + writeToFile(new File(schematicPath)); + } + + public void writeToFile(File schematicFile) throws IOException + { + FileOutputStream outputStream = new FileOutputStream(schematicFile); + CompressedStreamTools.writeCompressed(writeToNBT(false), outputStream); + //writeCompressed() probably closes the stream on its own - call close again just in case. + //Closing twice will not throw an exception. + outputStream.close(); + } +} diff --git a/StevenDimDoors/mod_pocketDim/schematic/WorldCopyOperation.java b/StevenDimDoors/mod_pocketDim/schematic/WorldCopyOperation.java new file mode 100644 index 0000000..d0c53d2 --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/schematic/WorldCopyOperation.java @@ -0,0 +1,75 @@ +package StevenDimDoors.mod_pocketDim.schematic; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public class WorldCopyOperation extends WorldOperation +{ + private int originX; + private int originY; + private int originZ; + private int index; + private short[] blockIDs; + private byte[] metadata; + private NBTTagList tileEntities; + + public WorldCopyOperation() + { + super("WorldCopyOperation"); + blockIDs = null; + metadata = null; + tileEntities = new NBTTagList(); + } + + @Override + protected boolean start(World world, int x, int y, int z, int width, int height, int length) + { + index = 0; + originX = x; + originY = y; + originZ = z; + blockIDs = new short[width * height * length]; + metadata = new byte[width * height * length]; + return true; + } + + @Override + protected boolean applyToBlock(World world, int x, int y, int z) + { + blockIDs[index] = (short) world.getBlockId(x, y, z); + metadata[index] = (byte) world.getBlockMetadata(x, y, z); + + TileEntity tileEntity = world.getBlockTileEntity(x, y, z); + if (tileEntity != null) + { + //Extract tile entity data + NBTTagCompound tileTag = new NBTTagCompound(); + tileEntity.writeToNBT(tileTag); + //Translate the tile entity's position from the world's coordinate system + //to the schematic's coordinate system. + tileTag.setInteger("x", x - originX); + tileTag.setInteger("y", y - originY); + tileTag.setInteger("z", z - originZ); + tileEntities.appendTag(tileTag); + } + index++; //This works assuming the loops in WorldOperation are done in YZX order + return true; + } + + public short[] getBlockIDs() + { + return blockIDs; + } + + public byte[] getMetadata() + { + return metadata; + } + + public NBTTagList getTileEntities() + { + return tileEntities; + } +} diff --git a/StevenDimDoors/mod_pocketDim/schematic/WorldOperation.java b/StevenDimDoors/mod_pocketDim/schematic/WorldOperation.java new file mode 100644 index 0000000..3d6f7fa --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/schematic/WorldOperation.java @@ -0,0 +1,64 @@ +package StevenDimDoors.mod_pocketDim.schematic; + +import net.minecraft.world.World; + +public abstract class WorldOperation { + + private String name; + + public WorldOperation(String name) + { + this.name = name; + } + + protected boolean start(World world, int x, int y, int z, int width, int height, int length) + { + return true; + } + + protected abstract boolean applyToBlock(World world, int x, int y, int z); + + protected boolean finish() + { + return true; + } + + 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)) + return false; + + int cx, cy, cz; + int limitX = x + width; + int limitY = y + height; + int limitZ = z + length; + + //The order of these loops is important. Don't change it! It's used to avoid calculating + //indeces in some schematic operations. The proper order is YZX. + for (cy = y; cy < limitY; cy++) + { + for (cz = z; cz < limitZ; cz++) + { + for (cx = x; cx < limitX; cx++) + { + if (!applyToBlock(world, cx, cy, cz)) + return false; + } + } + } + + return finish(); + } + + + public String getName() + { + return name; + } + + @Override + public String toString() + { + return name; + } +} From 77efb63a5fd1ee926b759c3ca4f256e8fa6a1d90 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sat, 27 Jul 2013 17:29:55 -0400 Subject: [PATCH 2/7] 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. --- .../schematic/CompactBoundsOperation.java | 2 +- .../schematic/InvalidSchematicException.java | 21 ++ .../mod_pocketDim/schematic/Schematic.java | 216 +++++++++++++++--- .../schematic/WorldCopyOperation.java | 5 +- .../schematic/WorldOperation.java | 4 +- 5 files changed, 212 insertions(+), 36 deletions(-) create mode 100644 StevenDimDoors/mod_pocketDim/schematic/InvalidSchematicException.java diff --git a/StevenDimDoors/mod_pocketDim/schematic/CompactBoundsOperation.java b/StevenDimDoors/mod_pocketDim/schematic/CompactBoundsOperation.java index 9b3ad88..7bb11bc 100644 --- a/StevenDimDoors/mod_pocketDim/schematic/CompactBoundsOperation.java +++ b/StevenDimDoors/mod_pocketDim/schematic/CompactBoundsOperation.java @@ -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; diff --git a/StevenDimDoors/mod_pocketDim/schematic/InvalidSchematicException.java b/StevenDimDoors/mod_pocketDim/schematic/InvalidSchematicException.java new file mode 100644 index 0000000..d1307a7 --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/schematic/InvalidSchematicException.java @@ -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); + } +} diff --git a/StevenDimDoors/mod_pocketDim/schematic/Schematic.java b/StevenDimDoors/mod_pocketDim/schematic/Schematic.java index 6e8b780..1c4c4d5 100644 --- a/StevenDimDoors/mod_pocketDim/schematic/Schematic.java +++ b/StevenDimDoors/mod_pocketDim/schematic/Schematic.java @@ -1,21 +1,29 @@ 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; protected short height; protected short length; - + protected short[] blocks; protected byte[] metadata; protected NBTTagList tileEntities = new NBTTagList(); @@ -29,7 +37,7 @@ public class Schematic { this.metadata = metadata; this.tileEntities = tileEntities; } - + private int calculateIndex(int x, int y, int z) { if (x < 0 || x >= width) @@ -38,30 +46,136 @@ public class Schematic { throw new IndexOutOfBoundsException("y must be non-negative and less than height"); if (z < 0 || z >= length) throw new IndexOutOfBoundsException("z must be non-negative and less than length"); - + return (y * width * length + z * width + x); } - + public short getBlockID(int x, int y, int z) { return blocks[calculateIndex(x, y, z)]; } - + public byte getBlockMetadata(int x, int y, int z) { return metadata[calculateIndex(x, y, z)]; } - + public NBTTagList getTileEntities() { 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) { if (doCompactBounds) @@ -75,17 +189,17 @@ public class Schematic { { fixedHeight = worldHeight - fixedY; } - + //Compact the area to be copied to remove empty borders CompactBoundsOperation compactor = new CompactBoundsOperation(); compactor.apply(world, x, fixedY, z, width, fixedHeight, length); Point3D minCorner = compactor.getMinCorner(); Point3D maxCorner = compactor.getMaxCorner(); - + short compactWidth = (short) (maxCorner.getX() - minCorner.getX() + 1); short compactHeight = (short) (maxCorner.getY() - minCorner.getY() + 1); short compactLength = (short) (maxCorner.getZ() - minCorner.getZ() + 1); - + return copyFromWorld(world, minCorner.getX(), minCorner.getY(), minCorner.getZ(), compactWidth, compactHeight, compactLength); } @@ -94,7 +208,7 @@ public class Schematic { return copyFromWorld(world, x, y, z, width, height, length); } } - + private static Schematic copyFromWorld(World world, int x, int y, int z, short width, short height, short length) { //Short and sweet ^_^ @@ -102,7 +216,7 @@ public class Schematic { copier.apply(world, x, y, z, width, height, length); return new Schematic(width, height, length, copier.getBlockIDs(), copier.getMetadata(), copier.getTileEntities()); } - + private static boolean encodeBlockIDs(short[] blocks, byte[] lowBits, byte[] highBits) { int index; @@ -118,40 +232,44 @@ 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; } - + public NBTTagCompound writeToNBT() { return writeToNBT(true); } - + private NBTTagCompound writeToNBT(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. - + NBTTagCompound schematicTag = new NBTTagCompound("Schematic"); schematicTag.setShort("Width", width); schematicTag.setShort("Length", length); schematicTag.setShort("Height", height); - + 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); - - schematicTag.setByteArray("Blocks", lowBytes); + + byte[] lowBits = new byte[blocks.length]; + byte[] highBits = new byte[(blocks.length >> 1) + 1]; + boolean hasExtendedIDs = encodeBlockIDs(blocks, lowBits, highBits); + + schematicTag.setByteArray("Blocks", lowBits); schematicTag.setByteArray("Data", metadata); - + if (hasExtendedIDs) { - schematicTag.setByteArray("AddBlocks", highBytes); + schematicTag.setByteArray("AddBlocks", highBits); } - + if (copyTileEntities) { //Used when the result of this function will be passed outside this class. @@ -166,12 +284,12 @@ public class Schematic { } return schematicTag; } - + public void writeToFile(String schematicPath) throws IOException { writeToFile(new File(schematicPath)); } - + public void writeToFile(File schematicFile) throws IOException { FileOutputStream outputStream = new FileOutputStream(schematicFile); @@ -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)); + } + } } diff --git a/StevenDimDoors/mod_pocketDim/schematic/WorldCopyOperation.java b/StevenDimDoors/mod_pocketDim/schematic/WorldCopyOperation.java index d0c53d2..fe49a78 100644 --- a/StevenDimDoors/mod_pocketDim/schematic/WorldCopyOperation.java +++ b/StevenDimDoors/mod_pocketDim/schematic/WorldCopyOperation.java @@ -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; } diff --git a/StevenDimDoors/mod_pocketDim/schematic/WorldOperation.java b/StevenDimDoors/mod_pocketDim/schematic/WorldOperation.java index 3d6f7fa..35798a5 100644 --- a/StevenDimDoors/mod_pocketDim/schematic/WorldOperation.java +++ b/StevenDimDoors/mod_pocketDim/schematic/WorldOperation.java @@ -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; From 8b64165e2eaf1c7eb8d35fd62b8ba05901e66935 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 28 Jul 2013 23:02:56 -0400 Subject: [PATCH 3/7] Improvements to Schematic Fixed bugs and made minor changes to Schematic. I've tested that it works properly now. It still needs to perform additional DD-specific functions and must be integrated to dungeon importing. --- .../mod_pocketDim/schematic/Schematic.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/StevenDimDoors/mod_pocketDim/schematic/Schematic.java b/StevenDimDoors/mod_pocketDim/schematic/Schematic.java index 1c4c4d5..a7baeb9 100644 --- a/StevenDimDoors/mod_pocketDim/schematic/Schematic.java +++ b/StevenDimDoors/mod_pocketDim/schematic/Schematic.java @@ -134,7 +134,7 @@ public class Schematic { 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) + if (volume > 2 * highBits.length && hasExtendedBlockIDs) throw new InvalidSchematicException("The schematic has extended block IDs for fewer blocks than its dimensions indicate."); blocks = new short[volume]; @@ -145,8 +145,8 @@ public class Schematic { 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]); + blocks[index] = (short) (((highBits[index >> 1] & 0x0F) << 8) + (lowBits[index] & 0xFF)); + blocks[index + 1] = (short) (((highBits[index >> 1] & 0xF0) << 4) + (lowBits[index + 1] & 0xFF)); } if (index < volume) { @@ -157,7 +157,9 @@ public class Schematic { { //Copy the blockIDs for (int index = 0; index < volume; index++) - blocks[index] = lowBits[index]; + { + blocks[index] = (short) (lowBits[index] & 0xFF); + } } //Get the list of tile entities @@ -301,6 +303,8 @@ public class Schematic { 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. + //It's not worth the trouble in this case. int index; int count; int dx, dy, dz; @@ -313,7 +317,8 @@ public class Schematic { { for (dx = 0; dx < width; dx++) { - world.setBlock(x + dx, y + dy, z + dz, blocks[index], metadata[index], 3); + //Don't cause block updates! + world.setBlock(x + dx, y + dy, z + dz, blocks[index], metadata[index], 2); index++; } } From 877678c945577c31d6fc766997696e33dd991bb9 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Mon, 29 Jul 2013 09:58:47 -0400 Subject: [PATCH 4/7] 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. --- .../commands/CommandCreateDungeonRift.java | 23 ++++ .../dungeon/DungeonSchematic.java | 112 ++++++++++++++++++ .../mod_pocketDim/dungeon/ModBlockFilter.java | 51 ++++++++ .../mod_pocketDim/helpers/DungeonHelper.java | 7 +- .../schematic/CompoundFilter.java | 58 +++++++++ .../schematic/ReplacementFilter.java | 75 ++++++++++++ .../mod_pocketDim/schematic/Schematic.java | 75 ++++++++++-- .../schematic/SchematicFilter.java | 55 +++++++++ 8 files changed, 446 insertions(+), 10 deletions(-) create mode 100644 StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java create mode 100644 StevenDimDoors/mod_pocketDim/dungeon/ModBlockFilter.java create mode 100644 StevenDimDoors/mod_pocketDim/schematic/CompoundFilter.java create mode 100644 StevenDimDoors/mod_pocketDim/schematic/ReplacementFilter.java create mode 100644 StevenDimDoors/mod_pocketDim/schematic/SchematicFilter.java diff --git a/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java b/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java index 84f2c06..281df90 100644 --- a/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java +++ b/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java @@ -1,13 +1,17 @@ package StevenDimDoors.mod_pocketDim.commands; import java.io.File; +import java.io.FileNotFoundException; import java.util.Collection; import net.minecraft.entity.player.EntityPlayer; +import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.DungeonGenerator; import StevenDimDoors.mod_pocketDim.LinkData; +import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; import StevenDimDoors.mod_pocketDim.helpers.dimHelper; +import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException; public class CommandCreateDungeonRift extends DDCommandBase { @@ -81,6 +85,25 @@ public class CommandCreateDungeonRift extends DDCommandBase link = dimHelper.instance.createPocket(link, true, true); dimHelper.dimList.get(link.destDimID).dungeonGenerator = result; sender.sendChatToPlayer("Created a rift to \"" + getSchematicName(result) + "\" dungeon (Dimension ID = " + link.destDimID + ")."); + + /*try { + DungeonSchematic dungeon; + if ((new File(result.schematicPath)).exists()) + { + dungeon = DungeonSchematic.readFromFile(result.schematicPath); + } + else + { + dungeon = DungeonSchematic.readFromResource(result.schematicPath); + } + dungeon.ApplyImportFilters(DDProperties.instance()); + dungeon.copyToWorld(sender.worldObj, x, y, z); + } catch (InvalidSchematicException e) { + e.printStackTrace(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + }*/ + } else { diff --git a/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java b/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java new file mode 100644 index 0000000..b364cbf --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java @@ -0,0 +1,112 @@ +package StevenDimDoors.mod_pocketDim.dungeon; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.DDProperties; +import StevenDimDoors.mod_pocketDim.schematic.CompoundFilter; +import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException; +import StevenDimDoors.mod_pocketDim.schematic.ReplacementFilter; +import StevenDimDoors.mod_pocketDim.schematic.Schematic; + +public class DungeonSchematic extends Schematic { + + private static final short MAX_VANILLA_BLOCK_ID = 158; + private static final short STANDARD_FABRIC_OF_REALITY_ID = 1973; + private static final short STANDARD_ETERNAL_FABRIC_ID = 220; + private static final short[] MOD_BLOCK_FILTER_EXCEPTIONS = new short[] { + STANDARD_FABRIC_OF_REALITY_ID, + STANDARD_ETERNAL_FABRIC_ID + }; + + private DungeonSchematic(Schematic source) + { + super(source); + } + + private DungeonSchematic() + { + //Used to create a dummy instance for readFromResource() + super((short) 0, (short) 0, (short) 0, null, null, null); + } + + public static DungeonSchematic readFromFile(String schematicPath) throws FileNotFoundException, InvalidSchematicException + { + return readFromFile(new File(schematicPath)); + } + + public static DungeonSchematic readFromFile(File schematicFile) throws FileNotFoundException, InvalidSchematicException + { + return readFromStream(new FileInputStream(schematicFile)); + } + + public static DungeonSchematic readFromResource(String resourcePath) throws InvalidSchematicException + { + //We need an instance of a class in the mod to retrieve a resource + DungeonSchematic empty = new DungeonSchematic(); + InputStream schematicStream = empty.getClass().getResourceAsStream(resourcePath); + return readFromStream(schematicStream); + } + + public static DungeonSchematic readFromStream(InputStream schematicStream) throws InvalidSchematicException + { + return new DungeonSchematic(Schematic.readFromStream(schematicStream)); + } + + public void ApplyImportFilters(DDProperties properties) + { + //Filter out mod blocks except some of our own + CompoundFilter standardizer = new CompoundFilter(); + standardizer.addFilter(new ModBlockFilter(MAX_VANILLA_BLOCK_ID, MOD_BLOCK_FILTER_EXCEPTIONS, + (short) properties.FabricBlockID, (byte) 0)); + + //Also convert standard DD block IDs to local versions + Map mapping = getAssignedToStandardIDMapping(properties); + + for (Entry entry : mapping.entrySet()) + { + if (entry.getKey() != entry.getValue()) + { + standardizer.addFilter(new ReplacementFilter(entry.getValue(), entry.getKey())); + } + } + standardizer.apply(this, this.blocks, this.metadata); + } + + public void ApplyExportFilters(DDProperties properties) + { + //Check if some block IDs assigned by Forge differ from our standard IDs + //If so, change the IDs to standard values + CompoundFilter standardizer = new CompoundFilter(); + Map mapping = getAssignedToStandardIDMapping(properties); + + for (Entry entry : mapping.entrySet()) + { + if (entry.getKey() != entry.getValue()) + { + standardizer.addFilter(new ReplacementFilter(entry.getKey(), entry.getValue())); + } + } + standardizer.apply(this, this.blocks, this.metadata); + } + + private Map getAssignedToStandardIDMapping(DDProperties properties) + { + //If we ever need this broadly or support other mods, this should be moved to a separate class + TreeMap mapping = new TreeMap(); + mapping.put((short) properties.FabricBlockID, STANDARD_FABRIC_OF_REALITY_ID); + mapping.put((short) properties.PermaFabricBlockID, STANDARD_ETERNAL_FABRIC_ID); + return mapping; + } + + public static DungeonSchematic copyFromWorld(World world, int x, int y, int z, short width, short height, short length, boolean doCompactBounds) + { + return new DungeonSchematic(Schematic.copyFromWorld(world, x, y, z, width, height, length, doCompactBounds)); + } +} diff --git a/StevenDimDoors/mod_pocketDim/dungeon/ModBlockFilter.java b/StevenDimDoors/mod_pocketDim/dungeon/ModBlockFilter.java new file mode 100644 index 0000000..c0ab099 --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/dungeon/ModBlockFilter.java @@ -0,0 +1,51 @@ +package StevenDimDoors.mod_pocketDim.dungeon; + +import net.minecraft.block.Block; +import StevenDimDoors.mod_pocketDim.schematic.SchematicFilter; + +public class ModBlockFilter extends SchematicFilter { + + private short maxVanillaBlockID; + private short[] exceptions; + private short replacementBlockID; + private byte replacementMetadata; + + public ModBlockFilter(short maxVanillaBlockID, short[] exceptions, short replacementBlockID, byte replacementMetadata) + { + super("ModBlockFilter"); + this.maxVanillaBlockID = maxVanillaBlockID; + this.exceptions = exceptions; + this.replacementBlockID = replacementBlockID; + this.replacementMetadata = replacementMetadata; + } + + @Override + protected boolean applyToBlock(int index, short[] blocks, byte[] metadata) + { + int k; + short currentID = blocks[index]; + if (currentID > maxVanillaBlockID || (currentID != 0 && Block.blocksList[currentID] == null)) + { + //This might be a mod block. Check if an exception exists. + for (k = 0; k < exceptions.length; k++) + { + if (currentID == exceptions[k]) + { + //Exception found, not considered a mod block + return false; + } + } + //No matching exception found. Replace the block. + blocks[index] = replacementBlockID; + metadata[index] = replacementMetadata; + return true; + } + return false; + } + + @Override + protected boolean terminates() + { + return false; + } +} diff --git a/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index f9cfa8d..9390339 100644 --- a/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -17,8 +17,8 @@ import StevenDimDoors.mod_pocketDim.DimData; import StevenDimDoors.mod_pocketDim.DungeonGenerator; import StevenDimDoors.mod_pocketDim.LinkData; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic; import StevenDimDoors.mod_pocketDim.items.itemDimDoor; -import StevenDimDoors.mod_pocketDim.schematic.Schematic; import StevenDimDoors.mod_pocketDim.util.WeightedContainer; public class DungeonHelper @@ -383,9 +383,10 @@ public class DungeonHelper try { short size = (short) 2 * MAX_EXPORT_RADIUS + 1; - Schematic schematic = Schematic.copyFromWorld(world, + DungeonSchematic dungeon = DungeonSchematic.copyFromWorld(world, centerX - MAX_EXPORT_RADIUS, centerY - MAX_EXPORT_RADIUS, centerZ - MAX_EXPORT_RADIUS, size, size, size, true); - schematic.writeToFile(exportPath); + dungeon.ApplyExportFilters(properties); + dungeon.writeToFile(exportPath); return true; } catch(Exception e) diff --git a/StevenDimDoors/mod_pocketDim/schematic/CompoundFilter.java b/StevenDimDoors/mod_pocketDim/schematic/CompoundFilter.java new file mode 100644 index 0000000..2de3ec6 --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/schematic/CompoundFilter.java @@ -0,0 +1,58 @@ +package StevenDimDoors.mod_pocketDim.schematic; + +import java.util.ArrayList; + +public class CompoundFilter extends SchematicFilter { + + private ArrayList filters; + + public CompoundFilter() + { + super("CompoundFilter"); + filters = new ArrayList(); + } + + 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; + } +} diff --git a/StevenDimDoors/mod_pocketDim/schematic/ReplacementFilter.java b/StevenDimDoors/mod_pocketDim/schematic/ReplacementFilter.java new file mode 100644 index 0000000..ba99304 --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/schematic/ReplacementFilter.java @@ -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; + } +} diff --git a/StevenDimDoors/mod_pocketDim/schematic/Schematic.java b/StevenDimDoors/mod_pocketDim/schematic/Schematic.java index a7baeb9..4f00dab 100644 --- a/StevenDimDoors/mod_pocketDim/schematic/Schematic.java +++ b/StevenDimDoors/mod_pocketDim/schematic/Schematic.java @@ -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(); + } + } } diff --git a/StevenDimDoors/mod_pocketDim/schematic/SchematicFilter.java b/StevenDimDoors/mod_pocketDim/schematic/SchematicFilter.java new file mode 100644 index 0000000..db3b374 --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/schematic/SchematicFilter.java @@ -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; + } +} From f4653d05226cff5fb6102bd6c27fdb8a69db96e8 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Tue, 30 Jul 2013 13:58:14 -0400 Subject: [PATCH 5/7] Improved and Integrated DungeonSchematic Improved DungeonSchematic to the point that it can replace SchematicLoader as our method of loading dungeons. Some of the code was copied over rather than refactored to save time. It's been subdivided so make it much more readable. Also, we can reimplement portions of it as WorldOperations later on further remove redudancy. Testing shows that there is one problem left to fix: door blocks are not being set up correctly at the moment. Rifts are being set up properly and attaching doors to rifts will show that dungeons continue to generate fine. Added classes to support DungeonSchematic and its additional filtering logic on import and export. SpecialBlockFinder handles listing the entrance, other doors in the dungeon, and end portal frames. FillContainersOperation is a WorldOperation that fills chests and dispensers. BlockRotator is a temporary class to hold transformMetadata() and transformPoint() until we rewrite that code later. Stripped out most of the code from SchematicLoader to ensure it's no longer used. The only remaining function sets up dungeon pockets. We can phase it out in a later version so as not to delay our release. Removed references to SchematicLoader in mod_pocketDim since it no longer needs to be instantiated. --- .../mod_pocketDim/SchematicLoader.java | 1283 +---------------- .../commands/CommandCreateDungeonRift.java | 6 +- .../dungeon/DungeonSchematic.java | 324 ++++- .../dungeon/FillContainersOperation.java | 75 + .../dungeon/SpecialBlockFinder.java | 107 ++ .../mod_pocketDim/helpers/DungeonHelper.java | 2 +- .../mod_pocketDim/helpers/dimHelper.java | 9 +- .../mod_pocketDim/mod_pocketDim.java | 5 - .../mod_pocketDim/schematic/BlockRotator.java | 755 ++++++++++ .../mod_pocketDim/schematic/Schematic.java | 33 +- .../schematic/WorldOperation.java | 12 + 11 files changed, 1338 insertions(+), 1273 deletions(-) create mode 100644 StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java create mode 100644 StevenDimDoors/mod_pocketDim/dungeon/SpecialBlockFinder.java create mode 100644 StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java diff --git a/StevenDimDoors/mod_pocketDim/SchematicLoader.java b/StevenDimDoors/mod_pocketDim/SchematicLoader.java index 332c535..8116cec 100644 --- a/StevenDimDoors/mod_pocketDim/SchematicLoader.java +++ b/StevenDimDoors/mod_pocketDim/SchematicLoader.java @@ -1,1235 +1,21 @@ package StevenDimDoors.mod_pocketDim; import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Random; +import java.io.FileNotFoundException; -import net.minecraft.block.Block; -import net.minecraft.block.BlockComparator; -import net.minecraft.block.BlockContainer; -import net.minecraft.block.BlockDoor; -import net.minecraft.block.BlockRedstoneRepeater; -import net.minecraft.block.BlockStairs; -import net.minecraft.entity.Entity; -import net.minecraft.inventory.IInventory; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.CompressedStreamTools; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.tileentity.TileEntityChest; -import net.minecraft.tileentity.TileEntityDispenser; -import net.minecraft.util.MathHelper; -import net.minecraft.util.WeightedRandomChestContent; import net.minecraft.world.World; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.storage.ExtendedBlockStorage; -import net.minecraftforge.common.ChestGenHooks; +import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; import StevenDimDoors.mod_pocketDim.helpers.dimHelper; -import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper; -import StevenDimDoors.mod_pocketDim.ticking.MobMonolith; +import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException; public class SchematicLoader -{ - private final static int EAST_DOOR_METADATA = 0; - private final static int SOUTH_DOOR_METADATA = 1; - private final static int WEST_DOOR_METADATA = 2; - private final static int NORTH_DOOR_METADATA = 3; - private final static int MAX_VANILLA_BLOCK_ID = 158; - - private DDProperties properties = DDProperties.instance(); +{ + private SchematicLoader() { } - public SchematicLoader() { } - - private static int transformMetadata(int metadata, int orientation, int blockID) + public static void generateDungeonPocket(LinkData link, DDProperties properties) { - if (DungeonHelper.instance().metadataFlipList.contains(blockID)) - { - switch (orientation) - { - case EAST_DOOR_METADATA: - - if (blockID == Block.hopperBlock.blockID) - { - switch (metadata) - { - case 2: - metadata = 5; - break; - case 3: - metadata = 4; - break; - case 4: - metadata = 2; - break; - case 5: - metadata = 3; - break; - } - } - if(Block.blocksList[blockID] instanceof BlockStairs) - { - - switch (metadata) - { - case 0: - metadata = 2; - break; - case 1: - metadata = 3; - break; - case 2: - metadata = 1; - break; - case 3: - metadata = 0; - break; - case 7: - metadata = 4; - break; - case 6: - metadata = 5; - break; - case 5: - metadata = 7; - break; - case 4: - metadata = 6; - break; - - } - } - - else if(blockID== Block.chest.blockID||blockID== Block.chestTrapped.blockID||blockID== Block.ladder.blockID) - { - switch (metadata) - { - - case 2: - metadata = 5; - break; - case 3: - metadata = 4; - break; - case 4: - metadata = 2; - break; - case 5: - metadata = 3; - break; - } - - } - else if (blockID==Block.vine.blockID) - { - switch (metadata) - { - - case 1: - metadata = 2; - break; - case 2: - metadata = 4; - break; - case 4: - metadata = 8; - break; - case 8: - metadata = 1; - break; - } - } - else if(blockID== Block.lever.blockID||blockID== Block.stoneButton.blockID||blockID== Block.woodenButton.blockID||blockID== Block.torchWood.blockID||blockID== Block.torchRedstoneIdle.blockID||blockID== Block.torchRedstoneActive.blockID) - { - switch (metadata) - { - case 12: - metadata = 9; - break; - case 11: - metadata = 10; - break; - case 10: - metadata = 12; - break; - case 9: - metadata = 11; - break; - case 2: - metadata = 4; - break; - case 3: - metadata = 2; - break; - case 1: - metadata = 3; - break; - case 4: - metadata = 1; - break; - } - } - else if(blockID== Block.pistonBase.blockID||blockID==Block.pistonExtension.blockID||blockID==Block.pistonStickyBase.blockID||blockID==Block.dispenser.blockID||blockID==Block.dropper.blockID) - { - switch (metadata) - { - case 4: - metadata = 2; - break; - case 5: - metadata = 3; - break; - case 13: - metadata = 11; - break; - case 12: - metadata = 10; - break; - case 3: - metadata = 4; - break; - case 2: - metadata = 5; - break; - case 11: - metadata = 12; - break; - case 10: - metadata = 13; - break; - } - } - else if(Block.blocksList[blockID] instanceof BlockRedstoneRepeater ||Block.blocksList[blockID] instanceof BlockDoor ||blockID== Block.tripWireSource.blockID||Block.blocksList[blockID] instanceof BlockComparator) - { - switch (metadata) - { - case 0: - metadata = 1; - break; - case 1: - metadata = 2; - break; - case 2: - metadata = 3; - break; - case 3: - metadata = 0; - break; - case 4: - metadata = 5; - break; - case 5: - metadata = 6; - break; - case 6: - metadata = 7; - break; - case 7: - metadata = 4; - break; - case 8: - metadata = 9; - break; - case 9: - metadata = 10; - break; - case 10: - metadata = 11; - break; - case 11: - metadata = 8; - break; - case 12: - metadata = 13; - break; - case 13: - metadata = 14; - break; - case 14: - metadata = 15; - break; - case 15: - metadata = 12; - break; - } - } - break; - case SOUTH_DOOR_METADATA: - - if (blockID == Block.hopperBlock.blockID) - { - switch (metadata) - { - case 2: - metadata = 3; - break; - case 3: - metadata = 2; - break; - case 4: - metadata = 5; - break; - case 5: - metadata = 4; - break; - } - } - - if(Block.blocksList[blockID] instanceof BlockStairs) - { - switch (metadata) - { - case 0: - metadata = 1; - break; - case 1: - metadata = 0; - break; - case 2: - metadata = 3; - break; - case 3: - metadata = 2; - break; - case 7: - metadata = 6; - break; - case 6: - metadata = 7; - break; - case 5: - metadata = 4; - break; - case 4: - metadata = 5; - break; - } - } - - else if(blockID== Block.chest.blockID||blockID== Block.chestTrapped.blockID||blockID==Block.ladder.blockID) - { - switch (metadata) - { - case 2: - metadata = 3; - break; - case 3: - metadata = 2; - break; - case 4: - metadata = 5; - break; - case 5: - metadata = 4; - break; - } - - } - - else if(blockID==Block.vine.blockID) - { - switch (metadata) - { - - case 1: - metadata = 4; - break; - case 2: - metadata = 8; - break; - case 4: - metadata = 1; - break; - case 8: - metadata = 2; - break; - } - } - - - - - else if(blockID== Block.lever.blockID||blockID== Block.torchWood.blockID||blockID== Block.torchRedstoneIdle.blockID||blockID== Block.torchRedstoneActive.blockID) - { - switch (metadata) - { - case 12: - metadata = 11; - break; - case 11: - metadata = 12; - break; - case 10: - metadata = 9; - break; - case 9: - metadata = 10; - break; - case 2: - metadata = 1; - break; - case 3: - metadata = 4; - break; - case 1: - metadata = 2; - break; - case 4: - metadata = 3; - - break; - - } - - } - - else if(blockID== Block.pistonBase.blockID||blockID==Block.pistonStickyBase.blockID||blockID==Block.dispenser.blockID||blockID==Block.dropper.blockID) - { - switch (metadata) - { - case 4: - metadata = 5; - break; - case 5: - metadata = 4; - break; - case 13: - metadata = 12; - break; - case 12: - metadata = 13; - break; - case 3: - metadata = 2; - break; - case 2: - metadata = 3; - break; - case 11: - metadata = 10; - break; - case 10: - metadata = 11; - break; - - } - - - - } - - else if(Block.blocksList[blockID] instanceof BlockRedstoneRepeater ||Block.blocksList[blockID] instanceof BlockDoor ||blockID== Block.tripWireSource.blockID||Block.blocksList[blockID] instanceof BlockComparator) - { - switch (metadata) - { - case 0: - metadata = 2; - break; - case 1: - metadata = 3; - break; - case 2: - metadata = 0; - break; - case 3: - metadata = 1; - break; - case 4: - metadata = 6; - break; - case 5: - metadata = 7; - break; - case 6: - metadata = 4; - break; - case 7: - metadata = 5; - break; - case 8: - metadata = 10; - break; - case 9: - metadata = 11; - break; - case 10: - metadata = 8; - break; - case 11: - metadata = 9; - break; - case 12: - metadata = 14; - break; - case 13: - metadata = 15; - break; - case 14: - metadata = 12; - break; - case 15: - metadata = 13; - break; - - - } - - - - } - - break; - case WEST_DOOR_METADATA: - - if (blockID == Block.hopperBlock.blockID) - { - switch (metadata) - { - case 2: - metadata = 4; - break; - case 3: - metadata = 5; - break; - case 4: - metadata = 3; - break; - case 5: - metadata = 2; - break; - } - } - - if(Block.blocksList[blockID] instanceof BlockStairs) - { - - switch (metadata) - { - case 2: - metadata = 0; - break; - case 3: - metadata = 1; - break; - case 1: - metadata = 2; - break; - case 0: - metadata = 3; - break; - case 4: - metadata = 7; - break; - case 5: - metadata = 6; - break; - case 7: - metadata = 5; - break; - case 6: - metadata = 4; - break; - - } - } - - else if(blockID== Block.chest.blockID||blockID== Block.chestTrapped.blockID||blockID==Block.ladder.blockID) - { - switch (metadata) - { - - case 2: - metadata = 4; - break; - case 3: - metadata = 5; - break; - case 4: - metadata = 3; - break; - case 5: - metadata = 2; - break; - - - - } - - } - - else if(blockID==Block.vine.blockID) - { - switch (metadata) - { - - case 1: - metadata = 8; - break; - case 2: - metadata = 1; - break; - case 4: - metadata = 2; - break; - case 8: - metadata = 4; - break; - } - } - - - - - else if(blockID== Block.lever.blockID||blockID== Block.torchWood.blockID||blockID== Block.torchRedstoneIdle.blockID||blockID== Block.torchRedstoneActive.blockID) - { - switch (metadata) - { - case 9: - metadata = 12; - break; - case 10: - metadata = 11; - break; - case 12: - metadata = 10; - break; - case 11: - metadata = 9; - break; - case 4: - metadata = 2; - break; - case 2: - metadata = 3; - break; - case 3: - metadata = 1; - break; - case 1: - metadata = 4; - - break; - - } - - } - - else if(blockID== Block.pistonBase.blockID||blockID==Block.pistonStickyBase.blockID||blockID==Block.dispenser.blockID||blockID==Block.dropper.blockID) - - { - switch (metadata) - { - case 2: - metadata = 4; - break; - case 3: - metadata = 5; - break; - case 11: - metadata = 13; - break; - case 10: - metadata = 12; - break; - case 4: - metadata = 3; - break; - case 5: - metadata = 2; - break; - case 12: - metadata = 11; - break; - case 13: - metadata = 10; - break; - } - } - else if(Block.blocksList[blockID] instanceof BlockRedstoneRepeater ||Block.blocksList[blockID] instanceof BlockDoor ||blockID== Block.tripWireSource.blockID||Block.blocksList[blockID] instanceof BlockComparator) - { - switch (metadata) - { - case 1: - metadata = 0; - break; - case 2: - metadata = 1; - break; - case 3: - metadata = 2; - break; - case 0: - metadata = 3; - break; - case 5: - metadata = 4; - break; - case 6: - metadata = 5; - break; - case 7: - metadata = 6; - break; - case 4: - metadata = 7; - break; - case 9: - metadata = 8; - break; - case 10: - metadata = 9; - break; - case 11: - metadata = 10; - break; - case 8: - metadata = 11; - break; - case 13: - metadata = 12; - break; - case 14: - metadata = 13; - break; - case 15: - metadata = 14; - break; - case 12: - metadata = 15; - break; - } - } - break; - case NORTH_DOOR_METADATA: - /** - * this is the default case- never need to change anything here - * - */ - break; - } - } - return metadata; - } - - public void generateSchematic(int riftX, int riftY, int riftZ, int orientation, int destDimID, int originDimID, String schematicPath) - { - short width = 0; - short height = 0; - short length = 0; - - //list of combined blockIds - short[] blocks = new short[0]; - - //block metaData - byte[] blockData = new byte[0]; - - //first 8 bits of the block ID - byte[] blockId = new byte[0]; - - //additional 4 bits of the block ID - byte[] addId = new byte[0]; - - //Variables for loading tile entities - boolean blockChanged = false; - NBTTagList tileEntities = null; - HashMap pointToTileEntityMap = new HashMap(); - - //the wooden door leading into the pocket - Point3D schematicEntrance = new Point3D(0,0,0); - - //the iron dim doors leading to more pockets - ArrayList sideLinks = new ArrayList(); - - //the wooden dim doors leading to the surface - ArrayList exitLinks = new ArrayList(); - - //the locations to spawn monoliths - ArrayList monolithSpawns = new ArrayList(); - - //load the schematic from disk - try - { - InputStream input; - String fname = schematicPath ; - - if(!(new File(fname).exists())) - { - //get file if its in the Jar - input = this.getClass().getResourceAsStream(fname); - } - else - { - //get file if in external library - System.out.println(new File(fname).exists()); - input = new FileInputStream(fname); - } - - NBTTagCompound schematicTag = CompressedStreamTools.readCompressed(input); - input.close(); //readCompressed() probably closes the stream anyway, but close again to be sure. - - //load size of schematic to generate - width = schematicTag.getShort("Width"); - height = schematicTag.getShort("Height"); - length = schematicTag.getShort("Length"); - - //load block info - blockId = schematicTag.getByteArray("Blocks"); - blockData = schematicTag.getByteArray("Data"); - addId = schematicTag.getByteArray("AddBlocks"); - - //create combined block list - blocks = new short[blockId.length]; - - //Combine the split block IDs into a single short[] - for (int index = 0; index < blockId.length; index++) - { - if ((index >> 1) >= addId.length) - { - blocks[index] = (short) (blockId[index] & 0xFF); - } - else - { - if ((index & 1) == 0) - { - blocks[index] = (short) (((addId[index >> 1] & 0x0F) << 8) + (blockId[index] & 0xFF)); - } - else - { - blocks[index] = (short) (((addId[index >> 1] & 0xF0) << 4) + (blockId[index] & 0xFF)); - } - } - } - - //Get the list of tile entities - tileEntities = schematicTag.getTagList("TileEntities"); - - //Map tile entity positions to the tile entity itself using a hash map - int count = tileEntities.tagCount(); - for (int index = 0; index < count; index++) - { - NBTTagCompound tileEntityData = (NBTTagCompound) tileEntities.tagAt(index); - Point3D location = new Point3D( - tileEntityData.getInteger("x"), - tileEntityData.getInteger("y"), - tileEntityData.getInteger("z")); - pointToTileEntityMap.put(location, tileEntityData); - } - } - catch (Exception e) - { - System.out.println("Error- could not find file "+schematicPath); - e.printStackTrace(); - } - - World world; - dimHelper.dimList.get(destDimID).hasBeenFilled = true; - - if (dimHelper.getWorld(destDimID) == null) - { - dimHelper.initDimension(destDimID); - } - world = dimHelper.getWorld(destDimID); + //TODO: Phase this function out in the next update. ~SenseiKiwi - //The following Random initialization code is based on code from ChunkProviderGenerate. - //It makes our generation depend on the world seed. - Random rand = new Random(world.getSeed()); - long factorA = rand.nextLong() / 2L * 2L + 1L; - long factorB = rand.nextLong() / 2L * 2L + 1L; - rand.setSeed((riftX >> 4) * factorA + (riftZ >> 4) * factorB ^ world.getSeed()); - - //Coordinates relative to the schematic, start at 0 and increase up to max width/height/length - int x, y, z; - Point3D schematicPoint = new Point3D(0, 0, 0); - - //The real point where a block will be placed - int realX, realY, realZ; - Point3D pocketPoint = new Point3D(0, 0, 0); - - //The central point of the pocket where we'll be placing the schematic - Point3D pocketCenter = new Point3D(riftX, riftY, riftZ); - Point3D zeroPoint = new Point3D(0, 0, 0); - - //The direction in which the player will enter. Will be set below. The direction is encoded using - //the same values as door metadata. Those values are not the same as Minecraft's cardinal directions. - int entryDirection = 0; - - //First loop through the schematic to load in all rift locations and Monolith spawn locations. - //Also find the entry door, which determines the final position and orientation of the dungeon. - for (y = 0; y < height; y++) - { - for (z = 0; z < length; z++) - { - for (x = 0; x < width; x++) - { - int index = y * width * length + z * width + x; - int indexBelow = (y - 1) * width * length + z * width + x; - int indexDoubleBelow = (y - 2) * width * length + z * width + x; - - int currentBlock = blocks[index]; - - //NBTTagList tileEntity = tileEntities; - //int size = tileEntity.tagCount(); - - if (currentBlock == Block.doorIron.blockID && indexBelow >= 0 && blocks[indexBelow] == Block.doorIron.blockID) - { - sideLinks.add(new Point3D(x, y, z)); - } - else if (currentBlock == Block.doorWood.blockID) - { - if (indexDoubleBelow >= 0 && blocks[indexDoubleBelow] == Block.sandStone.blockID && - blocks[indexBelow] == Block.doorWood.blockID) - { - exitLinks.add(new Point3D(x, y, z)); - } - else if (indexBelow >= 0 && blocks[indexBelow] == Block.doorWood.blockID) - { - schematicEntrance = new Point3D(x, y, z); - entryDirection = Math.abs(blockData[indexBelow] + 2) % 4; //TODO: Write a function for extracting a door's orientation from its metadata or at least change this to use bitwise operations. - } - } - else if (currentBlock == Block.endPortalFrame.blockID) - { - monolithSpawns.add(new Point3D(x, y, z)); - } - } - } - } - - //Loop to actually place the blocks - for (y = 0; y < height; y++) - { - schematicPoint.setY(y); - for (z = 0; z < length; z++) - { - schematicPoint.setZ(z); - for (x = 0; x < width; x++) - { - schematicPoint.setX(x); - - //Reinitialize pocketPoint with the current schematic coordinate system - pocketPoint.setX(x); - pocketPoint.setY(y); - pocketPoint.setZ(z); - //Transform pocketPoint into the pocket coordinate system - transformPoint(pocketPoint, schematicEntrance, orientation - entryDirection, pocketCenter); - //Store the transformed coordinates - realX = pocketPoint.getX(); - realY = pocketPoint.getY(); - realZ = pocketPoint.getZ(); - - int index = y * width * length + z * width + x; - int currentBlock = blocks[index]; - int blockMetadata = blockData[index]; - blockChanged = false; - - //replace tagging blocks with air, and mod blocks with FoR - if (currentBlock == Block.endPortalFrame.blockID) - { - currentBlock = 0; - blockChanged = true; - } - else if (currentBlock == DungeonHelper.FABRIC_OF_REALITY_EXPORT_ID) - { - currentBlock = mod_pocketDim.blockDimWall.blockID; - } - else if (currentBlock == DungeonHelper.PERMAFABRIC_EXPORT_ID) - { - currentBlock = mod_pocketDim.blockDimWallPerm.blockID; - } - else if ((Block.blocksList[currentBlock] == null && currentBlock != 0) || currentBlock > MAX_VANILLA_BLOCK_ID) - { - currentBlock = mod_pocketDim.blockDimWall.blockID; - blockChanged = true; - } - - //Place blocks and set metadata - if (currentBlock > 0) - { - int fixedMetadata; - - if (!blockChanged) - { - //Calculate new metadata for blocks that have orientations (e.g. doors, pistons) - //We're using a workaround to get the desired rotation relative to the schematic's entrance - fixedMetadata = transformMetadata(blockMetadata, (orientation + NORTH_DOOR_METADATA - entryDirection + 16) % 4, currentBlock); - } - else - { - //Don't include metadata for changed blocks. It's possible that the metadata belonged to a mod block. - //If we include it now, it could cause our Fabric of Reality to change into permafabric. - fixedMetadata = 0; - } - - //Convert vanilla doors to dim doors or place blocks - if (currentBlock == Block.doorIron.blockID) - { - setBlockDirectly(world, realX, realY, realZ, properties.DimensionalDoorID, fixedMetadata); - } - else if (currentBlock == Block.doorWood.blockID) - { - setBlockDirectly(world, realX, realY, realZ, properties.WarpDoorID, fixedMetadata); - } - else - { - setBlockDirectly(world, realX, realY, realZ, currentBlock, fixedMetadata); - } - - //Load the tile entity at this location if any exists, but only if the block wasn't changed - if (!blockChanged) - { - NBTTagCompound tileEntityData = pointToTileEntityMap.get(schematicPoint); - - if (tileEntityData != null) - { - //Change the tile entity's position - tileEntityData.setInteger("x", realX); - tileEntityData.setInteger("y", realY); - tileEntityData.setInteger("z", realZ); - //Load the tile entity into the world - world.setBlockTileEntity(realX, realY, realZ, TileEntity.createAndLoadEntity(tileEntityData)); - } - } - - //Fill empty chests and dispensers - if (Block.blocksList[currentBlock] instanceof BlockContainer) - { - TileEntity tileEntity = world.getBlockTileEntity(realX, realY, realZ); - - //Fill chests - if (tileEntity instanceof TileEntityChest) - { - TileEntityChest chest = (TileEntityChest) tileEntity; - if (isInventoryEmpty(chest)) - { - ChestGenHooks info = DDLoot.DungeonChestInfo; - WeightedRandomChestContent.generateChestContents(rand, info.getItems(rand), chest, info.getCount(rand)); - } - } - - //Fill dispensers - if (tileEntity instanceof TileEntityDispenser) - { - TileEntityDispenser dispenser = (TileEntityDispenser) tileEntity; - if (isInventoryEmpty(dispenser)) - { - dispenser.addItem(new ItemStack(Item.arrow, 64)); - } - } - } - } - } - } - } - - //We'll use an extra block here to restrict the scope of these variables to just inside the block - //This is to avoid declaration conflicts with the loops below - { - //Set the orientation of the rift exit - Point3D entranceRiftLocation = schematicEntrance.clone(); - transformPoint(entranceRiftLocation, schematicEntrance, orientation - entryDirection, pocketCenter); - LinkData sideLink = dimHelper.instance.getLinkDataFromCoords( - entranceRiftLocation.getX(), - entranceRiftLocation.getY(), - entranceRiftLocation.getZ(), - world); - sideLink.linkOrientation = world.getBlockMetadata( - entranceRiftLocation.getX(), - entranceRiftLocation.getY() - 1, - entranceRiftLocation.getZ()); - } - - //Generate the LinkData defined by the door placement, Iron Dim doors first - for(Point3D point : sideLinks) - { - int depth = dimHelper.instance.getDimDepth(originDimID) + 1; - int forwardNoise = MathHelper.getRandomIntegerInRange(rand, -50 * depth, 150 * depth); - int sidewaysNoise = MathHelper.getRandomIntegerInRange(rand, -10 * depth, 10 * depth); - - //Transform doorLocation to the pocket coordinate system - Point3D doorLocation = point.clone(); - transformPoint(doorLocation, schematicEntrance, orientation - entryDirection, pocketCenter); - int blockDirection = world.getBlockMetadata(doorLocation.getX(), doorLocation.getY() - 1, doorLocation.getZ()); - - //Rotate the link destination noise to point in the same direction as the door exit - //and add it to the door's location. Use EAST as the reference orientation since linkDestination - //is constructed as if pointing East. - Point3D linkDestination = new Point3D(forwardNoise, 0, sidewaysNoise); - transformPoint(linkDestination, zeroPoint, blockDirection - EAST_DOOR_METADATA, doorLocation); - - //Create the link between our current door and its intended exit in destination pocket - LinkData sideLink = new LinkData(destDimID, 0, - doorLocation.getX(), - doorLocation.getY(), - doorLocation.getZ(), - linkDestination.getX(), - linkDestination.getY() + 1, - linkDestination.getZ(), - true, blockDirection); - dimHelper.instance.createPocket(sideLink, true, true); - } - - //Generate linkData for wooden dim doors leading to the overworld - for(Point3D point : exitLinks) - { - try - { - //Transform doorLocation to the pocket coordinate system. - Point3D doorLocation = point.clone(); - transformPoint(doorLocation, schematicEntrance, orientation - entryDirection, pocketCenter); - int blockDirection = world.getBlockMetadata(doorLocation.getX(), doorLocation.getY() - 1, doorLocation.getZ()); - Point3D linkDestination = doorLocation.clone(); - - LinkData randomLink = dimHelper.instance.getRandomLinkData(false); - LinkData sideLink = new LinkData(destDimID, - dimHelper.dimList.get(originDimID).exitDimLink.destDimID, - doorLocation.getX(), - doorLocation.getY(), - doorLocation.getZ(), - linkDestination.getX(), - linkDestination.getY() + 1, - linkDestination.getZ(), - true, blockDirection); - - if (sideLink.destDimID == properties.LimboDimensionID) - { - sideLink.destDimID = 0; - } - else if ((rand.nextBoolean() && randomLink != null)) - { - sideLink.destDimID = randomLink.locDimID; - } - sideLink.destYCoord = yCoordHelper.getFirstUncovered(sideLink.destDimID, linkDestination.getX(), 10, linkDestination.getZ()); - - if (sideLink.destYCoord < 5) - { - sideLink.destYCoord = 70; - } - sideLink.linkOrientation = world.getBlockMetadata(linkDestination.getX(), linkDestination.getY() - 1, linkDestination.getZ()); - - dimHelper.instance.createLink(sideLink); - dimHelper.instance.createLink(sideLink.destDimID , - sideLink.locDimID, - sideLink.destXCoord, - sideLink.destYCoord, - sideLink.destZCoord, - sideLink.locXCoord, - sideLink.locYCoord, - sideLink.locZCoord, - dimHelper.instance.flipDoorMetadata(sideLink.linkOrientation)); - - if (world.getBlockId(linkDestination.getX(),linkDestination.getY() -3,linkDestination.getZ()) == properties.FabricBlockID) - { - setBlockDirectly(world,linkDestination.getX(),linkDestination.getY()-2,linkDestination.getZ(),Block.stoneBrick.blockID,0); - } - else - { - setBlockDirectly(world,linkDestination.getX(), - linkDestination.getY() - 2, - linkDestination.getZ(), - world.getBlockId(linkDestination.getX(), - linkDestination.getY() -3, - linkDestination.getZ()), - world.getBlockMetadata(linkDestination.getX(), - linkDestination.getY() -3, - linkDestination.getZ())); - } - } - catch (Exception E) - { - E.printStackTrace(); - } - } - - //Spawn monoliths - for(Point3D point : monolithSpawns) - { - //Transform the frame block's location to the pocket coordinate system - Point3D frameLocation = point.clone(); - transformPoint(frameLocation, schematicEntrance, orientation - entryDirection, pocketCenter); - - Entity mob = new MobMonolith(world); - mob.setLocationAndAngles(frameLocation.getX(), frameLocation.getY(), frameLocation.getZ(), 1, 1); //TODO: Why not set the angles to 0? @.@ ~SenseiKiwi - world.spawnEntityInWorld(mob); - } - } - - private static boolean isInventoryEmpty(IInventory inventory) - { - int size = inventory.getSizeInventory(); - for (int index = 0; index < size; index++) - { - if (inventory.getStackInSlot(index) != null) - { - return false; - } - } - return true; - } - - private static void transformPoint(Point3D position, Point3D srcOrigin, int angle, Point3D destOrigin) - { - //This function receives a position (e.g. point in schematic space), translates it relative - //to a source coordinate system (e.g. the point that will be the center of a schematic), - //then rotates and translates it to obtain the corresponding point in a destination - //coordinate system (e.g. the location of the entry rift in the pocket being generated). - //The result is returned by overwriting the original position so that new object references - //aren't needed. That way, repeated use of this function will not incur as much overhead. - - //Position is only overwritten at the end, so it's okay to provide it as srcOrigin or destOrigin as well. - - int tx = position.getX() - srcOrigin.getX(); - int ty = position.getY() - srcOrigin.getY(); - int tz = position.getZ() - srcOrigin.getZ(); - - //"int angle" specifies a rotation consistent with Minecraft's orientation system. - //That means each increment of 1 in angle would be a 90-degree clockwise turn. - //Given a starting direction A and a destination direction B, the rotation would be - //calculated by (B - A). - - //Adjust angle into the expected range - if (angle < 0) - { - int correction = -(angle / 4); - angle = angle + 4 * (correction + 1); - } - angle = angle % 4; - - int rx; - int rz; - switch (angle) - { - case 0: //No rotation - rx = tx; - rz = tz; - break; - case 1: //90 degrees clockwise - rx = -tz; - rz = tx; - break; - case 2: //180 degrees - rx = -tx; - rz = -tz; - break; - case 3: //270 degrees clockwise - rx = tz; - rz = -tx; - - break; - default: //This should never happen - throw new IllegalStateException("Invalid angle value. This should never happen!"); - } - - position.setX( rx + destOrigin.getX() ); - position.setY( ty + destOrigin.getY() ); - position.setZ( rz + destOrigin.getZ() ); - } - - public void generateDungeonPocket(LinkData link) - { String filePath=DungeonHelper.instance().defaultBreak.schematicPath; if(dimHelper.dimList.containsKey(link.destDimID)) { @@ -1239,39 +25,38 @@ public class SchematicLoader } filePath = dimHelper.dimList.get(link.destDimID).dungeonGenerator.schematicPath; } - this.generateSchematic(link.destXCoord, link.destYCoord, link.destZCoord, link.linkOrientation, link.destDimID, link.locDimID, filePath); - } - - - public void setBlockDirectly(World world, int x, int y, int z,int id, int metadata) - { - if (Block.blocksList[id] == null) - { - return; - } - - int cX = x >> 4; - int cZ = z >> 4; - int cY = y >> 4; - Chunk chunk; - - //TODO: This really seems odd to me. Like it's wrong. ~SenseiKiwi - int chunkX=(x % 16)< 0 ? ((x) % 16)+16 : ((x) % 16); - int chunkZ=((z) % 16)< 0 ? ((z) % 16)+16 : ((z) % 16); - + + //this.generateSchematic(link.destXCoord, link.destYCoord, link.destZCoord, link.linkOrientation, link.destDimID, link.locDimID, filePath); + try { - chunk = world.getChunkFromChunkCoords(cX, cZ); - if (chunk.getBlockStorageArray()[cY] == null) + int originDimID = link.locDimID; + int destDimID = link.destDimID; + DungeonSchematic dungeon; + if ((new File(filePath)).exists()) { - chunk.getBlockStorageArray()[cY] = new ExtendedBlockStorage(cY << 4, !world.provider.hasNoSky); + dungeon = DungeonSchematic.readFromFile(filePath); } - - - chunk.getBlockStorageArray()[cY].setExtBlockID(chunkX, (y) & 15, chunkZ, id); - chunk.getBlockStorageArray()[cY].setExtBlockMetadata(chunkX, (y) & 15, chunkZ, metadata); + else + { + dungeon = DungeonSchematic.readFromResource(filePath); + } + dungeon.applyImportFilters(properties); + + dimHelper.dimList.get(destDimID).hasBeenFilled = true; + if (dimHelper.getWorld(destDimID) == null) + { + dimHelper.initDimension(destDimID); + } + World world = dimHelper.getWorld(destDimID); + + dungeon.copyToWorld(world, new Point3D(link.destXCoord, link.destYCoord, link.destZCoord), link.linkOrientation, originDimID, destDimID); } - catch(Exception e) + catch (FileNotFoundException e) + { + e.printStackTrace(); + } + catch (InvalidSchematicException e) { e.printStackTrace(); } diff --git a/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java b/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java index 281df90..a924fd8 100644 --- a/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java +++ b/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java @@ -1,17 +1,13 @@ package StevenDimDoors.mod_pocketDim.commands; import java.io.File; -import java.io.FileNotFoundException; import java.util.Collection; import net.minecraft.entity.player.EntityPlayer; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.DungeonGenerator; import StevenDimDoors.mod_pocketDim.LinkData; -import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; import StevenDimDoors.mod_pocketDim.helpers.dimHelper; -import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException; public class CommandCreateDungeonRift extends DDCommandBase { @@ -96,7 +92,7 @@ public class CommandCreateDungeonRift extends DDCommandBase { dungeon = DungeonSchematic.readFromResource(result.schematicPath); } - dungeon.ApplyImportFilters(DDProperties.instance()); + dungeon.applyImportFilters(DDProperties.instance()); dungeon.copyToWorld(sender.worldObj, x, y, z); } catch (InvalidSchematicException e) { e.printStackTrace(); diff --git a/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java b/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java index b364cbf..5827666 100644 --- a/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java +++ b/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java @@ -4,25 +4,51 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; +import java.util.ArrayList; import java.util.Map; import java.util.Map.Entry; +import java.util.Random; import java.util.TreeMap; +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.MathHelper; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.DDProperties; +import StevenDimDoors.mod_pocketDim.LinkData; +import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.helpers.dimHelper; +import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper; +import StevenDimDoors.mod_pocketDim.schematic.BlockRotator; import StevenDimDoors.mod_pocketDim.schematic.CompoundFilter; import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException; import StevenDimDoors.mod_pocketDim.schematic.ReplacementFilter; import StevenDimDoors.mod_pocketDim.schematic.Schematic; +import StevenDimDoors.mod_pocketDim.ticking.MobMonolith; public class DungeonSchematic extends Schematic { private static final short MAX_VANILLA_BLOCK_ID = 158; private static final short STANDARD_FABRIC_OF_REALITY_ID = 1973; private static final short STANDARD_ETERNAL_FABRIC_ID = 220; + private static final short STANDARD_WARP_DOOR_ID = (short) Block.doorWood.blockID;//1975; + private static final short STANDARD_DIMENSIONAL_DOOR_ID = (short) Block.doorIron.blockID;//1970; + private static final short MONOLITH_SPAWN_MARKER_ID = (short) Block.endPortalFrame.blockID; + private static final short EXIT_DOOR_MARKER_ID = (short) Block.sandStone.blockID; + + private int orientation; + private Point3D entranceDoorLocation; + private ArrayList exitDoorLocations; + private ArrayList dimensionalDoorLocations; + private ArrayList monolithSpawnLocations; + private static final short[] MOD_BLOCK_FILTER_EXCEPTIONS = new short[] { STANDARD_FABRIC_OF_REALITY_ID, - STANDARD_ETERNAL_FABRIC_ID + STANDARD_ETERNAL_FABRIC_ID//, + //STANDARD_WARP_DOOR_ID, + //STANDARD_DIMENSIONAL_DOOR_ID }; private DungeonSchematic(Schematic source) @@ -30,6 +56,16 @@ public class DungeonSchematic extends Schematic { super(source); } + public int getOrientation() + { + return orientation; + } + + public Point3D getEntranceDoorLocation() + { + return entranceDoorLocation; + } + private DungeonSchematic() { //Used to create a dummy instance for readFromResource() @@ -59,8 +95,25 @@ public class DungeonSchematic extends Schematic { return new DungeonSchematic(Schematic.readFromStream(schematicStream)); } - public void ApplyImportFilters(DDProperties properties) + public void applyImportFilters(DDProperties properties) { + //Search for special blocks (warp doors, dim doors, and end portal frames that mark Monolith spawn points) + SpecialBlockFinder finder = new SpecialBlockFinder(STANDARD_WARP_DOOR_ID, STANDARD_DIMENSIONAL_DOOR_ID, + MONOLITH_SPAWN_MARKER_ID, EXIT_DOOR_MARKER_ID); + applyFilter(finder); + + orientation = (finder.getEntranceOrientation() + 2) & 3; //Flip the entrance's orientation to get the dungeon's orientation + entranceDoorLocation = finder.getEntranceDoorLocation(); + exitDoorLocations = finder.getExitDoorLocations(); + dimensionalDoorLocations = finder.getDimensionalDoorLocations(); + monolithSpawnLocations = finder.getMonolithSpawnLocations(); + + //TODO: Debug prints below. Please remove them before the next release! + System.out.println(entranceDoorLocation != null ? "Entrance was found" : "Entrance was not found"); + System.out.printf("There are %d exit doors in this room\n", exitDoorLocations.size()); + System.out.printf("There are %d dim doors in this room\n", dimensionalDoorLocations.size()); + System.out.printf("There are %d monolith spawn points in this room\n", monolithSpawnLocations.size()); + //Filter out mod blocks except some of our own CompoundFilter standardizer = new CompoundFilter(); standardizer.addFilter(new ModBlockFilter(MAX_VANILLA_BLOCK_ID, MOD_BLOCK_FILTER_EXCEPTIONS, @@ -76,11 +129,11 @@ public class DungeonSchematic extends Schematic { standardizer.addFilter(new ReplacementFilter(entry.getValue(), entry.getKey())); } } - standardizer.apply(this, this.blocks, this.metadata); + applyFilter(standardizer); } - public void ApplyExportFilters(DDProperties properties) - { + public void applyExportFilters(DDProperties properties) + { //Check if some block IDs assigned by Forge differ from our standard IDs //If so, change the IDs to standard values CompoundFilter standardizer = new CompoundFilter(); @@ -93,7 +146,14 @@ public class DungeonSchematic extends Schematic { standardizer.addFilter(new ReplacementFilter(entry.getKey(), entry.getValue())); } } - standardizer.apply(this, this.blocks, this.metadata); + + //Filter out mod blocks except some of our own + //This comes after ID standardization because the mod block filter relies on standardized IDs + standardizer.addFilter(new ModBlockFilter(MAX_VANILLA_BLOCK_ID, MOD_BLOCK_FILTER_EXCEPTIONS, + (short) properties.FabricBlockID, (byte) 0)); + + + applyFilter(standardizer); } private Map getAssignedToStandardIDMapping(DDProperties properties) @@ -102,6 +162,8 @@ public class DungeonSchematic extends Schematic { TreeMap mapping = new TreeMap(); mapping.put((short) properties.FabricBlockID, STANDARD_FABRIC_OF_REALITY_ID); mapping.put((short) properties.PermaFabricBlockID, STANDARD_ETERNAL_FABRIC_ID); + mapping.put((short) properties.WarpDoorID, STANDARD_WARP_DOOR_ID); + mapping.put((short) properties.DimensionalDoorID, STANDARD_DIMENSIONAL_DOOR_ID); return mapping; } @@ -109,4 +171,254 @@ public class DungeonSchematic extends Schematic { { return new DungeonSchematic(Schematic.copyFromWorld(world, x, y, z, width, height, length, doCompactBounds)); } + + public void copyToWorld(World world, Point3D pocketCenter, int dungeonOrientation, int originDimID, int destDimID) + { + //TODO: This function is an improvised solution so we can get the release moving. In the future, + //we should generalize block tranformations and implement support for them at the level of Schematic, + //then just use that support from DungeonSchematic instead of making this local fix. + //It might be easiest to support transformations using a WorldOperation + + final int turnAngle = dungeonOrientation - orientation; + + + int index; + int count; + int blockID; + int blockMeta; + int dx, dy, dz; + Point3D pocketPoint = new Point3D(0, 0, 0); + + //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++) + { + pocketPoint.setX(dx); + pocketPoint.setY(dy); + pocketPoint.setZ(dz); + blockID = blocks[index]; + BlockRotator.transformPoint(pocketPoint, entranceDoorLocation, turnAngle, pocketCenter); + blockMeta = BlockRotator.transformMetadata(metadata[index], turnAngle + BlockRotator.NORTH_DOOR_METADATA, blockID); + + //In the future, we might want to make this more efficient by building whole chunks at a time + setBlockDirectly(world, pocketPoint.getX(), pocketPoint.getY(), pocketPoint.getZ(), blockID, blockMeta); + 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 + pocketPoint.setX(tileTag.getInteger("x")); + pocketPoint.setY(tileTag.getInteger("y")); + pocketPoint.setZ(tileTag.getInteger("z")); + BlockRotator.transformPoint(pocketPoint, entranceDoorLocation, turnAngle, pocketCenter); + tileTag.setInteger("x", pocketPoint.getX()); + tileTag.setInteger("y", pocketPoint.getY()); + tileTag.setInteger("z", pocketPoint.getZ()); + //Load the tile entity and put it in the world + world.setBlockTileEntity(pocketPoint.getX(), pocketPoint.getY(), pocketPoint.getZ(), TileEntity.createAndLoadEntity(tileTag)); + } + + setUpDungeon(world, pocketCenter, turnAngle, originDimID, destDimID); + } + + private void setUpDungeon(World world, Point3D pocketCenter, int turnAngle, int originDimID, int destDimID) + { + //The following Random initialization code is based on code from ChunkProviderGenerate. + //It makes our generation depend on the world seed. + Random random = new Random(world.getSeed()); + long factorA = random.nextLong() / 2L * 2L + 1L; + long factorB = random.nextLong() / 2L * 2L + 1L; + random.setSeed((pocketCenter.getX() >> 4) * factorA + (pocketCenter.getZ() >> 4) * factorB ^ world.getSeed()); + + //Transform dungeon corners + Point3D minCorner = new Point3D(0, 0, 0); + Point3D maxCorner = new Point3D(width - 1, height - 1, length - 1); + transformCorners(entranceDoorLocation, pocketCenter, turnAngle, minCorner, maxCorner); + + //Fill empty chests and dispensers + FillContainersOperation filler = new FillContainersOperation(random); + filler.apply(world, minCorner, maxCorner); + + //Set up entrance door rift + setUpEntranceDoorLink(world, entranceDoorLocation, turnAngle, pocketCenter); + + //Set up link data for dimensional doors + for (Point3D location : dimensionalDoorLocations) + { + setUpDimensionalDoorLink(world, location, entranceDoorLocation, turnAngle, pocketCenter, originDimID, destDimID, random); + } + + //Set up link data for exit door + for (Point3D location : exitDoorLocations) + { + setUpExitDoorLink(world, location, entranceDoorLocation, turnAngle, pocketCenter, originDimID, destDimID, random); + } + + //Remove end portal frames and spawn Monoliths + for (Point3D location : monolithSpawnLocations) + { + spawnMonolith(world, location, entranceDoorLocation, turnAngle, pocketCenter); + } + } + + private static void transformCorners(Point3D schematicEntrance, Point3D pocketCenter, int turnAngle, Point3D minCorner, Point3D maxCorner) + { + int temp; + BlockRotator.transformPoint(minCorner, schematicEntrance, turnAngle, pocketCenter); + BlockRotator.transformPoint(maxCorner, schematicEntrance, turnAngle, pocketCenter); + if (minCorner.getX() > maxCorner.getX()) + { + temp = minCorner.getX(); + minCorner.setX(maxCorner.getX()); + maxCorner.setX(temp); + } + if (minCorner.getY() > maxCorner.getY()) + { + temp = minCorner.getY(); + minCorner.setY(maxCorner.getY()); + maxCorner.setY(temp); + } + if (minCorner.getZ() > maxCorner.getZ()) + { + temp = minCorner.getZ(); + minCorner.setZ(maxCorner.getZ()); + maxCorner.setZ(temp); + } + } + + private static void setUpEntranceDoorLink(World world, Point3D entrance, int rotation, Point3D pocketCenter) + { + //Set the orientation of the rift exit + Point3D entranceRiftLocation = entrance.clone(); + BlockRotator.transformPoint(entranceRiftLocation, entrance, rotation, pocketCenter); + LinkData sideLink = dimHelper.instance.getLinkDataFromCoords( + entranceRiftLocation.getX(), + entranceRiftLocation.getY(), + entranceRiftLocation.getZ(), + world); + sideLink.linkOrientation = world.getBlockMetadata( + entranceRiftLocation.getX(), + entranceRiftLocation.getY() - 1, + entranceRiftLocation.getZ()); + } + + private static void setUpExitDoorLink(World world, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter, int originDimID, int destDimID, Random random) + { + try + { + //TODO: Hax, remove this later + DDProperties properties = DDProperties.instance(); + + //Transform doorLocation to the pocket coordinate system. + Point3D location = point.clone(); + BlockRotator.transformPoint(location, entrance, rotation, pocketCenter); + int blockDirection = world.getBlockMetadata(location.getX(), location.getY() - 1, location.getZ()); + Point3D linkDestination = location.clone(); + + LinkData randomLink = dimHelper.instance.getRandomLinkData(false); + LinkData sideLink = new LinkData(destDimID, + dimHelper.dimList.get(originDimID).exitDimLink.destDimID, + location.getX(), + location.getY(), + location.getZ(), + linkDestination.getX(), + linkDestination.getY() + 1, + linkDestination.getZ(), + true, blockDirection); + + if (sideLink.destDimID == properties.LimboDimensionID) + { + sideLink.destDimID = 0; + } + else if ((random.nextBoolean() && randomLink != null)) + { + sideLink.destDimID = randomLink.locDimID; + } + sideLink.destYCoord = yCoordHelper.getFirstUncovered(sideLink.destDimID, linkDestination.getX(), 10, linkDestination.getZ()); + + if (sideLink.destYCoord < 5) + { + sideLink.destYCoord = 70; + } + sideLink.linkOrientation = world.getBlockMetadata(linkDestination.getX(), linkDestination.getY() - 1, linkDestination.getZ()); + + dimHelper.instance.createLink(sideLink); + dimHelper.instance.createLink(sideLink.destDimID , + sideLink.locDimID, + sideLink.destXCoord, + sideLink.destYCoord, + sideLink.destZCoord, + sideLink.locXCoord, + sideLink.locYCoord, + sideLink.locZCoord, + dimHelper.instance.flipDoorMetadata(sideLink.linkOrientation)); + + if (world.getBlockId(linkDestination.getX(), linkDestination.getY() - 3, linkDestination.getZ()) == properties.FabricBlockID) + { + setBlockDirectly(world, linkDestination.getX(), linkDestination.getY() - 2, linkDestination.getZ(), Block.stoneBrick.blockID, 0); + } + else + { + setBlockDirectly(world,linkDestination.getX(), linkDestination.getY() - 2, linkDestination.getZ(), + world.getBlockId(linkDestination.getX(), linkDestination.getY() - 3, linkDestination.getZ()), + world.getBlockMetadata(linkDestination.getX(), linkDestination.getY() - 3, linkDestination.getZ())); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + private static void setUpDimensionalDoorLink(World world, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter, int originDimID, int destDimID, Random random) + { + int depth = dimHelper.instance.getDimDepth(originDimID) + 1; + int forwardNoise = MathHelper.getRandomIntegerInRange(random, -50 * depth, 150 * depth); + int sidewaysNoise = MathHelper.getRandomIntegerInRange(random, -10 * depth, 10 * depth); + + //Transform doorLocation to the pocket coordinate system + Point3D location = point.clone(); + BlockRotator.transformPoint(location, entrance, rotation, pocketCenter); + int blockDirection = world.getBlockMetadata(location.getX(), location.getY() - 1, location.getZ()); + + //Rotate the link destination noise to point in the same direction as the door exit + //and add it to the door's location. Use EAST as the reference orientation since linkDestination + //is constructed as if pointing East. + Point3D linkDestination = new Point3D(forwardNoise, 0, sidewaysNoise); + Point3D zeroPoint = new Point3D(0, 0, 0); + BlockRotator.transformPoint(linkDestination, zeroPoint, blockDirection - BlockRotator.EAST_DOOR_METADATA, location); + + //Create the link between our current door and its intended exit in destination pocket + LinkData sideLink = new LinkData(destDimID, 0, + location.getX(), + location.getY(), + location.getZ(), + linkDestination.getX(), + linkDestination.getY() + 1, + linkDestination.getZ(), + true, blockDirection); + dimHelper.instance.createPocket(sideLink, true, true); + } + + private static void spawnMonolith(World world, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter) + { + //Transform the frame block's location to the pocket coordinate system + Point3D location = point.clone(); + BlockRotator.transformPoint(location, entrance, rotation, pocketCenter); + //Remove frame block + setBlockDirectly(world, location.getX(), location.getY(), location.getZ(), 0, 0); + //Spawn Monolith + Entity mob = new MobMonolith(world); + mob.setLocationAndAngles(location.getX(), location.getY(), location.getZ(), 1, 1); + world.spawnEntityInWorld(mob); + } } diff --git a/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java b/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java new file mode 100644 index 0000000..7979eaf --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java @@ -0,0 +1,75 @@ +package StevenDimDoors.mod_pocketDim.dungeon; + +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockContainer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityChest; +import net.minecraft.tileentity.TileEntityDispenser; +import net.minecraft.util.WeightedRandomChestContent; +import net.minecraft.world.World; +import net.minecraftforge.common.ChestGenHooks; +import StevenDimDoors.mod_pocketDim.DDLoot; +import StevenDimDoors.mod_pocketDim.schematic.WorldOperation; + +public class FillContainersOperation extends WorldOperation +{ + private Random random; + + public FillContainersOperation(Random random) + { + super("FillContainersOperation"); + this.random = random; + } + + @Override + protected boolean applyToBlock(World world, int x, int y, int z) + { + int blockID = world.getBlockId(x, y, z); + + //Fill empty chests and dispensers + if (Block.blocksList[blockID] instanceof BlockContainer) + { + TileEntity tileEntity = world.getBlockTileEntity(x, y, z); + + //Fill chests + if (tileEntity instanceof TileEntityChest) + { + TileEntityChest chest = (TileEntityChest) tileEntity; + if (isInventoryEmpty(chest)) + { + ChestGenHooks info = DDLoot.DungeonChestInfo; + WeightedRandomChestContent.generateChestContents(random, info.getItems(random), chest, info.getCount(random)); + } + } + + //Fill dispensers + if (tileEntity instanceof TileEntityDispenser) + { + TileEntityDispenser dispenser = (TileEntityDispenser) tileEntity; + if (isInventoryEmpty(dispenser)) + { + dispenser.addItem(new ItemStack(Item.arrow, 64)); + } + } + } + return true; + } + + private static boolean isInventoryEmpty(IInventory inventory) + { + int size = inventory.getSizeInventory(); + for (int index = 0; index < size; index++) + { + if (inventory.getStackInSlot(index) != null) + { + return false; + } + } + return true; + } +} diff --git a/StevenDimDoors/mod_pocketDim/dungeon/SpecialBlockFinder.java b/StevenDimDoors/mod_pocketDim/dungeon/SpecialBlockFinder.java new file mode 100644 index 0000000..94efdd4 --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/dungeon/SpecialBlockFinder.java @@ -0,0 +1,107 @@ +package StevenDimDoors.mod_pocketDim.dungeon; + +import java.util.ArrayList; + +import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.schematic.Schematic; +import StevenDimDoors.mod_pocketDim.schematic.SchematicFilter; + +public class SpecialBlockFinder extends SchematicFilter { + + private short warpDoorID; + private short dimensionalDoorID; + private short monolithSpawnMarkerID; + private short exitMarkerID; + private int entranceOrientation; + private Schematic schematic; + private Point3D entranceDoorLocation; + private ArrayList exitDoorLocations; + private ArrayList dimensionalDoorLocations; + private ArrayList monolithSpawnLocations; + + public SpecialBlockFinder(short warpDoorID, short dimensionalDoorID, short monolithSpawnMarkerID, short exitMarkerID) + { + super("SpecialBlockFinder"); + this.warpDoorID = warpDoorID; + this.dimensionalDoorID = dimensionalDoorID; + this.monolithSpawnMarkerID = monolithSpawnMarkerID; + this.exitMarkerID = exitMarkerID; + this.entranceDoorLocation = null; + this.entranceOrientation = 0; + this.exitDoorLocations = new ArrayList(); + this.dimensionalDoorLocations = new ArrayList(); + this.monolithSpawnLocations = new ArrayList(); + this.schematic = null; + } + + public int getEntranceOrientation() { + return entranceOrientation; + } + + public Point3D getEntranceDoorLocation() { + return entranceDoorLocation; + } + + public ArrayList getExitDoorLocations() { + return exitDoorLocations; + } + + public ArrayList getDimensionalDoorLocations() { + return dimensionalDoorLocations; + } + + public ArrayList getMonolithSpawnLocations() { + return monolithSpawnLocations; + } + + @Override + protected boolean initialize(Schematic schematic, short[] blocks, byte[] metadata) + { + this.schematic = schematic; + return true; + } + + @Override + protected boolean applyToBlock(int index, short[] blocks, byte[] metadata) + { + int indexBelow; + int indexDoubleBelow; + + if (blocks[index] == monolithSpawnMarkerID) + { + monolithSpawnLocations.add(schematic.calculatePoint(index)); + } + else if (blocks[index] == dimensionalDoorID) + { + indexBelow = schematic.calculateIndexBelow(index); + if (indexBelow >= 0 && blocks[indexBelow] == dimensionalDoorID) + { + dimensionalDoorLocations.add(schematic.calculatePoint(index)); + } + } + else if (blocks[index] == warpDoorID) + { + indexBelow = schematic.calculateIndexBelow(index); + if (indexBelow >= 0 && blocks[indexBelow] == warpDoorID) + { + indexDoubleBelow = schematic.calculateIndexBelow(indexBelow); + if (indexDoubleBelow >= 0 && blocks[indexDoubleBelow] == exitMarkerID) + { + exitDoorLocations.add(schematic.calculatePoint(index)); + } + else if (entranceDoorLocation == null) + { + entranceDoorLocation = schematic.calculatePoint(index); + entranceOrientation = (metadata[indexBelow] & 3); + } + } + } + return true; + } + + @Override + protected boolean terminates() + { + return false; + } +} diff --git a/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 9390339..6812ccf 100644 --- a/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -385,7 +385,7 @@ public class DungeonHelper short size = (short) 2 * MAX_EXPORT_RADIUS + 1; DungeonSchematic dungeon = DungeonSchematic.copyFromWorld(world, centerX - MAX_EXPORT_RADIUS, centerY - MAX_EXPORT_RADIUS, centerZ - MAX_EXPORT_RADIUS, size, size, size, true); - dungeon.ApplyExportFilters(properties); + dungeon.applyExportFilters(properties); dungeon.writeToFile(exportPath); return true; } diff --git a/StevenDimDoors/mod_pocketDim/helpers/dimHelper.java b/StevenDimDoors/mod_pocketDim/helpers/dimHelper.java index 795c603..dd4e979 100644 --- a/StevenDimDoors/mod_pocketDim/helpers/dimHelper.java +++ b/StevenDimDoors/mod_pocketDim/helpers/dimHelper.java @@ -39,6 +39,7 @@ import StevenDimDoors.mod_pocketDim.LinkData; import StevenDimDoors.mod_pocketDim.ObjectSaveInputStream; import StevenDimDoors.mod_pocketDim.PacketHandler; import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.SchematicLoader; import StevenDimDoors.mod_pocketDim.TileEntityRift; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.world.LimboProvider; @@ -759,12 +760,8 @@ public class dimHelper extends DimensionManager } else if(!data.hasBeenFilled&&data.isPocket&&data.isDimRandomRift) { - //System.out.println("genning dungeon pocket"); - - - mod_pocketDim.loader.generateDungeonPocket(incomingLink); + SchematicLoader.generateDungeonPocket(incomingLink, properties); data.hasBeenFilled=true; - } } @@ -778,7 +775,7 @@ public class dimHelper extends DimensionManager mod_pocketDim.hasInitDims=true; this.load(); - if(!this.dimList.isEmpty()) + if(!dimHelper.dimList.isEmpty()) { diff --git a/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 21c47d7..d360e09 100644 --- a/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -32,7 +32,6 @@ import StevenDimDoors.mod_pocketDim.commands.CommandExportDungeon; import StevenDimDoors.mod_pocketDim.commands.CommandPrintDimensionData; import StevenDimDoors.mod_pocketDim.commands.CommandPruneDimensions; import StevenDimDoors.mod_pocketDim.commands.CommandResetDungeons; -import StevenDimDoors.mod_pocketDim.helpers.BlockRotationHelper; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; import StevenDimDoors.mod_pocketDim.helpers.dimHelper; import StevenDimDoors.mod_pocketDim.items.ItemBlockDimWall; @@ -98,9 +97,7 @@ public class mod_pocketDim @Instance("PocketDimensions") public static mod_pocketDim instance = new mod_pocketDim(); - public static SchematicLoader loader; public static pocketTeleporter teleporter; - public static BlockRotationHelper rotationHelper; public static Block transientDoor; public static Block ExitDoor; @@ -169,11 +166,9 @@ public class mod_pocketDim //These fields MUST be initialized after properties are loaded to prevent //instances from holding onto null references to the properties. - loader = new SchematicLoader(); teleporter = new pocketTeleporter(); tracker = new PlayerRespawnTracker(); riftGen = new RiftGenerator(); - rotationHelper = new BlockRotationHelper(); } @Init diff --git a/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java b/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java new file mode 100644 index 0000000..8960c23 --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java @@ -0,0 +1,755 @@ +package StevenDimDoors.mod_pocketDim.schematic; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockComparator; +import net.minecraft.block.BlockDoor; +import net.minecraft.block.BlockRedstoneRepeater; +import net.minecraft.block.BlockStairs; +import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; + +public class BlockRotator +{ + //This class is temporary. It's just a place in which to hold the old block rotation and transformation code + //until we can rewrite it. + + public final static int EAST_DOOR_METADATA = 0; + private final static int SOUTH_DOOR_METADATA = 1; + private final static int WEST_DOOR_METADATA = 2; + public final static int NORTH_DOOR_METADATA = 3; + + public static int transformMetadata(int metadata, int orientation, int blockID) + { + //TODO: Replace this horrible function with something prettier. We promise we will for the next version, + //after switching to MC 1.6. + + //Hax to fix negative orientations + orientation += 1 << 16; + orientation %= 4; + + if (DungeonHelper.instance().metadataFlipList.contains(blockID)) + { + switch (orientation) + { + case EAST_DOOR_METADATA: + + if (blockID == Block.hopperBlock.blockID) + { + switch (metadata) + { + case 2: + metadata = 5; + break; + case 3: + metadata = 4; + break; + case 4: + metadata = 2; + break; + case 5: + metadata = 3; + break; + } + } + if(Block.blocksList[blockID] instanceof BlockStairs) + { + + switch (metadata) + { + case 0: + metadata = 2; + break; + case 1: + metadata = 3; + break; + case 2: + metadata = 1; + break; + case 3: + metadata = 0; + break; + case 7: + metadata = 4; + break; + case 6: + metadata = 5; + break; + case 5: + metadata = 7; + break; + case 4: + metadata = 6; + break; + + } + } + + else if(blockID== Block.chest.blockID||blockID== Block.chestTrapped.blockID||blockID== Block.ladder.blockID) + { + switch (metadata) + { + + case 2: + metadata = 5; + break; + case 3: + metadata = 4; + break; + case 4: + metadata = 2; + break; + case 5: + metadata = 3; + break; + } + + } + else if (blockID==Block.vine.blockID) + { + switch (metadata) + { + + case 1: + metadata = 2; + break; + case 2: + metadata = 4; + break; + case 4: + metadata = 8; + break; + case 8: + metadata = 1; + break; + } + } + else if(blockID== Block.lever.blockID||blockID== Block.stoneButton.blockID||blockID== Block.woodenButton.blockID||blockID== Block.torchWood.blockID||blockID== Block.torchRedstoneIdle.blockID||blockID== Block.torchRedstoneActive.blockID) + { + switch (metadata) + { + case 12: + metadata = 9; + break; + case 11: + metadata = 10; + break; + case 10: + metadata = 12; + break; + case 9: + metadata = 11; + break; + case 2: + metadata = 4; + break; + case 3: + metadata = 2; + break; + case 1: + metadata = 3; + break; + case 4: + metadata = 1; + break; + } + } + else if(blockID== Block.pistonBase.blockID||blockID==Block.pistonExtension.blockID||blockID==Block.pistonStickyBase.blockID||blockID==Block.dispenser.blockID||blockID==Block.dropper.blockID) + { + switch (metadata) + { + case 4: + metadata = 2; + break; + case 5: + metadata = 3; + break; + case 13: + metadata = 11; + break; + case 12: + metadata = 10; + break; + case 3: + metadata = 4; + break; + case 2: + metadata = 5; + break; + case 11: + metadata = 12; + break; + case 10: + metadata = 13; + break; + } + } + else if(Block.blocksList[blockID] instanceof BlockRedstoneRepeater ||Block.blocksList[blockID] instanceof BlockDoor ||blockID== Block.tripWireSource.blockID||Block.blocksList[blockID] instanceof BlockComparator) + { + switch (metadata) + { + case 0: + metadata = 1; + break; + case 1: + metadata = 2; + break; + case 2: + metadata = 3; + break; + case 3: + metadata = 0; + break; + case 4: + metadata = 5; + break; + case 5: + metadata = 6; + break; + case 6: + metadata = 7; + break; + case 7: + metadata = 4; + break; + case 8: + metadata = 9; + break; + case 9: + metadata = 10; + break; + case 10: + metadata = 11; + break; + case 11: + metadata = 8; + break; + case 12: + metadata = 13; + break; + case 13: + metadata = 14; + break; + case 14: + metadata = 15; + break; + case 15: + metadata = 12; + break; + } + } + break; + case SOUTH_DOOR_METADATA: + + if (blockID == Block.hopperBlock.blockID) + { + switch (metadata) + { + case 2: + metadata = 3; + break; + case 3: + metadata = 2; + break; + case 4: + metadata = 5; + break; + case 5: + metadata = 4; + break; + } + } + + if(Block.blocksList[blockID] instanceof BlockStairs) + { + switch (metadata) + { + case 0: + metadata = 1; + break; + case 1: + metadata = 0; + break; + case 2: + metadata = 3; + break; + case 3: + metadata = 2; + break; + case 7: + metadata = 6; + break; + case 6: + metadata = 7; + break; + case 5: + metadata = 4; + break; + case 4: + metadata = 5; + break; + } + } + + else if(blockID== Block.chest.blockID||blockID== Block.chestTrapped.blockID||blockID==Block.ladder.blockID) + { + switch (metadata) + { + case 2: + metadata = 3; + break; + case 3: + metadata = 2; + break; + case 4: + metadata = 5; + break; + case 5: + metadata = 4; + break; + } + + } + + else if(blockID==Block.vine.blockID) + { + switch (metadata) + { + + case 1: + metadata = 4; + break; + case 2: + metadata = 8; + break; + case 4: + metadata = 1; + break; + case 8: + metadata = 2; + break; + } + } + + + + + else if(blockID== Block.lever.blockID||blockID== Block.torchWood.blockID||blockID== Block.torchRedstoneIdle.blockID||blockID== Block.torchRedstoneActive.blockID) + { + switch (metadata) + { + case 12: + metadata = 11; + break; + case 11: + metadata = 12; + break; + case 10: + metadata = 9; + break; + case 9: + metadata = 10; + break; + case 2: + metadata = 1; + break; + case 3: + metadata = 4; + break; + case 1: + metadata = 2; + break; + case 4: + metadata = 3; + + break; + + } + + } + + else if(blockID== Block.pistonBase.blockID||blockID==Block.pistonStickyBase.blockID||blockID==Block.dispenser.blockID||blockID==Block.dropper.blockID) + { + switch (metadata) + { + case 4: + metadata = 5; + break; + case 5: + metadata = 4; + break; + case 13: + metadata = 12; + break; + case 12: + metadata = 13; + break; + case 3: + metadata = 2; + break; + case 2: + metadata = 3; + break; + case 11: + metadata = 10; + break; + case 10: + metadata = 11; + break; + + } + + + + } + + else if(Block.blocksList[blockID] instanceof BlockRedstoneRepeater ||Block.blocksList[blockID] instanceof BlockDoor ||blockID== Block.tripWireSource.blockID||Block.blocksList[blockID] instanceof BlockComparator) + { + switch (metadata) + { + case 0: + metadata = 2; + break; + case 1: + metadata = 3; + break; + case 2: + metadata = 0; + break; + case 3: + metadata = 1; + break; + case 4: + metadata = 6; + break; + case 5: + metadata = 7; + break; + case 6: + metadata = 4; + break; + case 7: + metadata = 5; + break; + case 8: + metadata = 10; + break; + case 9: + metadata = 11; + break; + case 10: + metadata = 8; + break; + case 11: + metadata = 9; + break; + case 12: + metadata = 14; + break; + case 13: + metadata = 15; + break; + case 14: + metadata = 12; + break; + case 15: + metadata = 13; + break; + + + } + + + + } + + break; + case WEST_DOOR_METADATA: + + if (blockID == Block.hopperBlock.blockID) + { + switch (metadata) + { + case 2: + metadata = 4; + break; + case 3: + metadata = 5; + break; + case 4: + metadata = 3; + break; + case 5: + metadata = 2; + break; + } + } + + if(Block.blocksList[blockID] instanceof BlockStairs) + { + + switch (metadata) + { + case 2: + metadata = 0; + break; + case 3: + metadata = 1; + break; + case 1: + metadata = 2; + break; + case 0: + metadata = 3; + break; + case 4: + metadata = 7; + break; + case 5: + metadata = 6; + break; + case 7: + metadata = 5; + break; + case 6: + metadata = 4; + break; + + } + } + + else if(blockID== Block.chest.blockID||blockID== Block.chestTrapped.blockID||blockID==Block.ladder.blockID) + { + switch (metadata) + { + + case 2: + metadata = 4; + break; + case 3: + metadata = 5; + break; + case 4: + metadata = 3; + break; + case 5: + metadata = 2; + break; + + + + } + + } + + else if(blockID==Block.vine.blockID) + { + switch (metadata) + { + + case 1: + metadata = 8; + break; + case 2: + metadata = 1; + break; + case 4: + metadata = 2; + break; + case 8: + metadata = 4; + break; + } + } + + + + + else if(blockID== Block.lever.blockID||blockID== Block.torchWood.blockID||blockID== Block.torchRedstoneIdle.blockID||blockID== Block.torchRedstoneActive.blockID) + { + switch (metadata) + { + case 9: + metadata = 12; + break; + case 10: + metadata = 11; + break; + case 12: + metadata = 10; + break; + case 11: + metadata = 9; + break; + case 4: + metadata = 2; + break; + case 2: + metadata = 3; + break; + case 3: + metadata = 1; + break; + case 1: + metadata = 4; + + break; + + } + + } + + else if(blockID== Block.pistonBase.blockID||blockID==Block.pistonStickyBase.blockID||blockID==Block.dispenser.blockID||blockID==Block.dropper.blockID) + + { + switch (metadata) + { + case 2: + metadata = 4; + break; + case 3: + metadata = 5; + break; + case 11: + metadata = 13; + break; + case 10: + metadata = 12; + break; + case 4: + metadata = 3; + break; + case 5: + metadata = 2; + break; + case 12: + metadata = 11; + break; + case 13: + metadata = 10; + break; + } + } + else if(Block.blocksList[blockID] instanceof BlockRedstoneRepeater ||Block.blocksList[blockID] instanceof BlockDoor ||blockID== Block.tripWireSource.blockID||Block.blocksList[blockID] instanceof BlockComparator) + { + switch (metadata) + { + case 1: + metadata = 0; + break; + case 2: + metadata = 1; + break; + case 3: + metadata = 2; + break; + case 0: + metadata = 3; + break; + case 5: + metadata = 4; + break; + case 6: + metadata = 5; + break; + case 7: + metadata = 6; + break; + case 4: + metadata = 7; + break; + case 9: + metadata = 8; + break; + case 10: + metadata = 9; + break; + case 11: + metadata = 10; + break; + case 8: + metadata = 11; + break; + case 13: + metadata = 12; + break; + case 14: + metadata = 13; + break; + case 15: + metadata = 14; + break; + case 12: + metadata = 15; + break; + } + } + break; + case NORTH_DOOR_METADATA: + /** + * this is the default case- never need to change anything here + * + */ + break; + } + } + return metadata; + } + + public static void transformPoint(Point3D position, Point3D srcOrigin, int angle, Point3D destOrigin) + { + //This function receives a position (e.g. point in schematic space), translates it relative + //to a source coordinate system (e.g. the point that will be the center of a schematic), + //then rotates and translates it to obtain the corresponding point in a destination + //coordinate system (e.g. the location of the entry rift in the pocket being generated). + //The result is returned by overwriting the original position so that new object references + //aren't needed. That way, repeated use of this function will not incur as much overhead. + + //Position is only overwritten at the end, so it's okay to provide it as srcOrigin or destOrigin as well. + + int tx = position.getX() - srcOrigin.getX(); + int ty = position.getY() - srcOrigin.getY(); + int tz = position.getZ() - srcOrigin.getZ(); + + //"int angle" specifies a rotation consistent with Minecraft's orientation system. + //That means each increment of 1 in angle would be a 90-degree clockwise turn. + //Given a starting direction A and a destination direction B, the rotation would be + //calculated by (B - A). + + //Adjust angle into the expected range + if (angle < 0) + { + int correction = -(angle / 4); + angle = angle + 4 * (correction + 1); + } + angle = angle % 4; + + int rx; + int rz; + switch (angle) + { + case 0: //No rotation + rx = tx; + rz = tz; + break; + case 1: //90 degrees clockwise + rx = -tz; + rz = tx; + break; + case 2: //180 degrees + rx = -tx; + rz = -tz; + break; + case 3: //270 degrees clockwise + rx = tz; + rz = -tx; + + break; + default: //This should never happen + throw new IllegalStateException("Invalid angle value. This should never happen!"); + } + + position.setX( rx + destOrigin.getX() ); + position.setY( ty + destOrigin.getY() ); + position.setZ( rz + destOrigin.getZ() ); + } +} diff --git a/StevenDimDoors/mod_pocketDim/schematic/Schematic.java b/StevenDimDoors/mod_pocketDim/schematic/Schematic.java index 4f00dab..c81da44 100644 --- a/StevenDimDoors/mod_pocketDim/schematic/Schematic.java +++ b/StevenDimDoors/mod_pocketDim/schematic/Schematic.java @@ -53,7 +53,7 @@ public class Schematic { this.tileEntities = source.tileEntities; } - protected int calculateIndex(int x, int y, int z) + public 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"); @@ -64,7 +64,38 @@ public class Schematic { return (y * width * length + z * width + x); } + + public Point3D calculatePoint(int index) + { + int y = index / (width * length); + index -= y * width * length; + int z = index / width; + index -= z * width; + int x = index; + + return new Point3D(x, y, z); + } + + public int calculateIndexBelow(int index) + { + return index - (width * length); + } + public short getWidth() + { + return width; + } + + public short getHeight() + { + return height; + } + + public short getLength() + { + return length; + } + public short getBlockID(int x, int y, int z) { return blocks[calculateIndex(x, y, z)]; diff --git a/StevenDimDoors/mod_pocketDim/schematic/WorldOperation.java b/StevenDimDoors/mod_pocketDim/schematic/WorldOperation.java index 35798a5..85fa540 100644 --- a/StevenDimDoors/mod_pocketDim/schematic/WorldOperation.java +++ b/StevenDimDoors/mod_pocketDim/schematic/WorldOperation.java @@ -1,5 +1,6 @@ package StevenDimDoors.mod_pocketDim.schematic; +import StevenDimDoors.mod_pocketDim.Point3D; import net.minecraft.world.World; public abstract class WorldOperation { @@ -23,6 +24,17 @@ public abstract class WorldOperation { return true; } + public boolean apply(World world, Point3D minCorner, Point3D maxCorner) + { + int x = minCorner.getX(); + int y = minCorner.getY(); + int z = minCorner.getZ(); + int width = maxCorner.getX() - x + 1; + int height = maxCorner.getY() - y + 1; + int length = maxCorner.getZ() - z + 1; + return apply(world, x, y, z, width, height, length); + } + public boolean apply(World world, int x, int y, int z, int width, int height, int length) { if (!initialize(world, x, y, z, width, height, length)) From 766336a25943f06969d1a1b2754d41938f61591f Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Tue, 30 Jul 2013 17:57:05 -0400 Subject: [PATCH 6/7] Fixed Door Bugs Fixed the bugs that caused doors not to appear right in dungeons. First there was a bug with filters that caused them not to replace blocks properly. I made some changes to SchematicFilter and its derived classes so that the implementations are a little more intuitive. That should prevent those bugs in any future derived classes. Then doors wouldn't rotate properly. DD was never designed to rotate dimensional doors. I added code to BlockRotator for that and shifted some code from DungeonHelper to BlockRotator. More coherence, less coupling! --- StevenDimDoors/mod_pocketDim/Point3D.java | 6 +++ .../commands/CommandCreateDungeonRift.java | 19 ------- .../dungeon/DungeonSchematic.java | 8 +-- .../dungeon/SpecialBlockFinder.java | 14 +++-- .../mod_pocketDim/helpers/DungeonHelper.java | 42 --------------- .../mod_pocketDim/schematic/BlockRotator.java | 54 ++++++++++++++++--- .../schematic/CompoundFilter.java | 6 +-- .../schematic/ReplacementFilter.java | 1 + .../schematic/SchematicFilter.java | 2 +- 9 files changed, 71 insertions(+), 81 deletions(-) diff --git a/StevenDimDoors/mod_pocketDim/Point3D.java b/StevenDimDoors/mod_pocketDim/Point3D.java index 5d4a03d..2fd653e 100644 --- a/StevenDimDoors/mod_pocketDim/Point3D.java +++ b/StevenDimDoors/mod_pocketDim/Point3D.java @@ -101,4 +101,10 @@ public class Point3D implements Serializable { } return hash; } + + @Override + public String toString() + { + return "(" + x + ", " + "y" + ", " + z + ")"; + } } \ No newline at end of file diff --git a/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java b/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java index a924fd8..84f2c06 100644 --- a/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java +++ b/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java @@ -81,25 +81,6 @@ public class CommandCreateDungeonRift extends DDCommandBase link = dimHelper.instance.createPocket(link, true, true); dimHelper.dimList.get(link.destDimID).dungeonGenerator = result; sender.sendChatToPlayer("Created a rift to \"" + getSchematicName(result) + "\" dungeon (Dimension ID = " + link.destDimID + ")."); - - /*try { - DungeonSchematic dungeon; - if ((new File(result.schematicPath)).exists()) - { - dungeon = DungeonSchematic.readFromFile(result.schematicPath); - } - else - { - dungeon = DungeonSchematic.readFromResource(result.schematicPath); - } - dungeon.applyImportFilters(DDProperties.instance()); - dungeon.copyToWorld(sender.worldObj, x, y, z); - } catch (InvalidSchematicException e) { - e.printStackTrace(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - }*/ - } else { diff --git a/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java b/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java index 5827666..35e245b 100644 --- a/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java +++ b/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java @@ -46,7 +46,7 @@ public class DungeonSchematic extends Schematic { private static final short[] MOD_BLOCK_FILTER_EXCEPTIONS = new short[] { STANDARD_FABRIC_OF_REALITY_ID, - STANDARD_ETERNAL_FABRIC_ID//, + STANDARD_ETERNAL_FABRIC_ID //STANDARD_WARP_DOOR_ID, //STANDARD_DIMENSIONAL_DOOR_ID }; @@ -108,12 +108,6 @@ public class DungeonSchematic extends Schematic { dimensionalDoorLocations = finder.getDimensionalDoorLocations(); monolithSpawnLocations = finder.getMonolithSpawnLocations(); - //TODO: Debug prints below. Please remove them before the next release! - System.out.println(entranceDoorLocation != null ? "Entrance was found" : "Entrance was not found"); - System.out.printf("There are %d exit doors in this room\n", exitDoorLocations.size()); - System.out.printf("There are %d dim doors in this room\n", dimensionalDoorLocations.size()); - System.out.printf("There are %d monolith spawn points in this room\n", monolithSpawnLocations.size()); - //Filter out mod blocks except some of our own CompoundFilter standardizer = new CompoundFilter(); standardizer.addFilter(new ModBlockFilter(MAX_VANILLA_BLOCK_ID, MOD_BLOCK_FILTER_EXCEPTIONS, diff --git a/StevenDimDoors/mod_pocketDim/dungeon/SpecialBlockFinder.java b/StevenDimDoors/mod_pocketDim/dungeon/SpecialBlockFinder.java index 94efdd4..ff8fffb 100644 --- a/StevenDimDoors/mod_pocketDim/dungeon/SpecialBlockFinder.java +++ b/StevenDimDoors/mod_pocketDim/dungeon/SpecialBlockFinder.java @@ -70,16 +70,22 @@ public class SpecialBlockFinder extends SchematicFilter { if (blocks[index] == monolithSpawnMarkerID) { monolithSpawnLocations.add(schematic.calculatePoint(index)); + return true; } - else if (blocks[index] == dimensionalDoorID) + if (blocks[index] == dimensionalDoorID) { indexBelow = schematic.calculateIndexBelow(index); if (indexBelow >= 0 && blocks[indexBelow] == dimensionalDoorID) { dimensionalDoorLocations.add(schematic.calculatePoint(index)); + return true; + } + else + { + return false; } } - else if (blocks[index] == warpDoorID) + if (blocks[index] == warpDoorID) { indexBelow = schematic.calculateIndexBelow(index); if (indexBelow >= 0 && blocks[indexBelow] == warpDoorID) @@ -88,15 +94,17 @@ public class SpecialBlockFinder extends SchematicFilter { if (indexDoubleBelow >= 0 && blocks[indexDoubleBelow] == exitMarkerID) { exitDoorLocations.add(schematic.calculatePoint(index)); + return true; } else if (entranceDoorLocation == null) { entranceDoorLocation = schematic.calculatePoint(index); entranceOrientation = (metadata[indexBelow] & 3); + return true; } } } - return true; + return false; } @Override diff --git a/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 6812ccf..3103893 100644 --- a/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -9,7 +9,6 @@ import java.util.HashSet; import java.util.Random; import java.util.regex.Pattern; -import net.minecraft.block.Block; import net.minecraft.util.WeightedRandom; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.DDProperties; @@ -69,8 +68,6 @@ public class DungeonHelper private ArrayList pistonTraps = new ArrayList(); private ArrayList exits = new ArrayList(); - public ArrayList metadataFlipList = new ArrayList(); - public ArrayList metadataNextList = new ArrayList(); public DungeonGenerator defaultBreak = new DungeonGenerator(DEFAULT_DUNGEON_WEIGHT, "/schematics/somethingBroke.schematic", true); public DungeonGenerator defaultUp = new DungeonGenerator(DEFAULT_DUNGEON_WEIGHT, "/schematics/simpleStairsUp.schematic", true); @@ -112,7 +109,6 @@ public class DungeonHelper { copyfile.copyFile("/mods/DimDoors/text/How_to_add_dungeons.txt", file.getAbsolutePath() + "/How_to_add_dungeons.txt"); } - registerFlipBlocks(); importCustomDungeons(properties.CustomSchematicDirectory); registerBaseDungeons(); } @@ -257,44 +253,6 @@ public class DungeonHelper } } - public void registerFlipBlocks() - { - metadataFlipList.add(Block.dispenser.blockID); - metadataFlipList.add(Block.stairsStoneBrick.blockID); - metadataFlipList.add(Block.lever.blockID); - metadataFlipList.add(Block.stoneButton.blockID); - metadataFlipList.add(Block.redstoneRepeaterIdle.blockID); - metadataFlipList.add(Block.redstoneRepeaterActive.blockID); - metadataFlipList.add(Block.tripWireSource.blockID); - metadataFlipList.add(Block.torchWood.blockID); - metadataFlipList.add(Block.torchRedstoneIdle.blockID); - metadataFlipList.add(Block.torchRedstoneActive.blockID); - metadataFlipList.add(Block.doorIron.blockID); - metadataFlipList.add(Block.doorWood.blockID); - metadataFlipList.add(Block.pistonBase.blockID); - metadataFlipList.add(Block.pistonStickyBase.blockID); - metadataFlipList.add(Block.pistonExtension.blockID); - metadataFlipList.add(Block.redstoneComparatorIdle.blockID); - metadataFlipList.add(Block.redstoneComparatorActive.blockID); - metadataFlipList.add(Block.signPost.blockID); - metadataFlipList.add(Block.signWall.blockID); - metadataFlipList.add(Block.skull.blockID); - metadataFlipList.add(Block.ladder.blockID); - metadataFlipList.add(Block.vine.blockID); - metadataFlipList.add(Block.anvil.blockID); - metadataFlipList.add(Block.chest.blockID); - metadataFlipList.add(Block.chestTrapped.blockID); - metadataFlipList.add(Block.hopperBlock.blockID); - metadataFlipList.add(Block.stairsNetherBrick.blockID); - metadataFlipList.add(Block.stairsCobblestone.blockID); - metadataFlipList.add(Block.stairsNetherBrick.blockID); - metadataFlipList.add(Block.stairsNetherQuartz.blockID); - metadataFlipList.add(Block.stairsSandStone.blockID); - - metadataNextList.add(Block.redstoneRepeaterIdle.blockID); - metadataNextList.add(Block.redstoneRepeaterActive.blockID); - } - public void registerBaseDungeons() { hubs.add(new DungeonGenerator(2 * DEFAULT_DUNGEON_WEIGHT, "/schematics/4WayBasicHall.schematic", false)); diff --git a/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java b/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java index 8960c23..fded0a4 100644 --- a/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java +++ b/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java @@ -1,12 +1,15 @@ package StevenDimDoors.mod_pocketDim.schematic; +import java.util.ArrayList; + import net.minecraft.block.Block; import net.minecraft.block.BlockComparator; import net.minecraft.block.BlockDoor; import net.minecraft.block.BlockRedstoneRepeater; import net.minecraft.block.BlockStairs; import StevenDimDoors.mod_pocketDim.Point3D; -import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.blocks.dimDoor; public class BlockRotator { @@ -17,17 +20,56 @@ public class BlockRotator private final static int SOUTH_DOOR_METADATA = 1; private final static int WEST_DOOR_METADATA = 2; public final static int NORTH_DOOR_METADATA = 3; + + private final static ArrayList metadataFlipList = new ArrayList(); + + static + { + metadataFlipList.add(Block.dispenser.blockID); + metadataFlipList.add(Block.stairsStoneBrick.blockID); + metadataFlipList.add(Block.lever.blockID); + metadataFlipList.add(Block.stoneButton.blockID); + metadataFlipList.add(Block.redstoneRepeaterIdle.blockID); + metadataFlipList.add(Block.redstoneRepeaterActive.blockID); + metadataFlipList.add(Block.tripWireSource.blockID); + metadataFlipList.add(Block.torchWood.blockID); + metadataFlipList.add(Block.torchRedstoneIdle.blockID); + metadataFlipList.add(Block.torchRedstoneActive.blockID); + metadataFlipList.add(Block.doorIron.blockID); + metadataFlipList.add(Block.doorWood.blockID); + metadataFlipList.add(Block.pistonBase.blockID); + metadataFlipList.add(Block.pistonStickyBase.blockID); + metadataFlipList.add(Block.pistonExtension.blockID); + metadataFlipList.add(Block.redstoneComparatorIdle.blockID); + metadataFlipList.add(Block.redstoneComparatorActive.blockID); + metadataFlipList.add(Block.signPost.blockID); + metadataFlipList.add(Block.signWall.blockID); + metadataFlipList.add(Block.skull.blockID); + metadataFlipList.add(Block.ladder.blockID); + metadataFlipList.add(Block.vine.blockID); + metadataFlipList.add(Block.anvil.blockID); + metadataFlipList.add(Block.chest.blockID); + metadataFlipList.add(Block.chestTrapped.blockID); + metadataFlipList.add(Block.hopperBlock.blockID); + metadataFlipList.add(Block.stairsNetherBrick.blockID); + metadataFlipList.add(Block.stairsCobblestone.blockID); + metadataFlipList.add(Block.stairsNetherBrick.blockID); + metadataFlipList.add(Block.stairsNetherQuartz.blockID); + metadataFlipList.add(Block.stairsSandStone.blockID); + metadataFlipList.add(mod_pocketDim.dimDoor.blockID); + metadataFlipList.add(mod_pocketDim.ExitDoor.blockID); + } public static int transformMetadata(int metadata, int orientation, int blockID) { //TODO: Replace this horrible function with something prettier. We promise we will for the next version, - //after switching to MC 1.6. + //after switching to MC 1.6. PADRE, PLEASE FORGIVE ME. //Hax to fix negative orientations orientation += 1 << 16; orientation %= 4; - if (DungeonHelper.instance().metadataFlipList.contains(blockID)) + if (metadataFlipList.contains(blockID)) { switch (orientation) { @@ -183,7 +225,7 @@ public class BlockRotator break; } } - else if(Block.blocksList[blockID] instanceof BlockRedstoneRepeater ||Block.blocksList[blockID] instanceof BlockDoor ||blockID== Block.tripWireSource.blockID||Block.blocksList[blockID] instanceof BlockComparator) + else if(Block.blocksList[blockID] instanceof BlockRedstoneRepeater || Block.blocksList[blockID] instanceof BlockDoor || Block.blocksList[blockID] instanceof dimDoor || blockID== Block.tripWireSource.blockID || Block.blocksList[blockID] instanceof BlockComparator) { switch (metadata) { @@ -402,7 +444,7 @@ public class BlockRotator } - else if(Block.blocksList[blockID] instanceof BlockRedstoneRepeater ||Block.blocksList[blockID] instanceof BlockDoor ||blockID== Block.tripWireSource.blockID||Block.blocksList[blockID] instanceof BlockComparator) + else if(Block.blocksList[blockID] instanceof BlockRedstoneRepeater ||Block.blocksList[blockID] instanceof BlockDoor || Block.blocksList[blockID] instanceof dimDoor || blockID== Block.tripWireSource.blockID||Block.blocksList[blockID] instanceof BlockComparator) { switch (metadata) { @@ -629,7 +671,7 @@ public class BlockRotator break; } } - else if(Block.blocksList[blockID] instanceof BlockRedstoneRepeater ||Block.blocksList[blockID] instanceof BlockDoor ||blockID== Block.tripWireSource.blockID||Block.blocksList[blockID] instanceof BlockComparator) + else if(Block.blocksList[blockID] instanceof BlockRedstoneRepeater ||Block.blocksList[blockID] instanceof BlockDoor || Block.blocksList[blockID] instanceof dimDoor || blockID== Block.tripWireSource.blockID||Block.blocksList[blockID] instanceof BlockComparator) { switch (metadata) { diff --git a/StevenDimDoors/mod_pocketDim/schematic/CompoundFilter.java b/StevenDimDoors/mod_pocketDim/schematic/CompoundFilter.java index 2de3ec6..882faa5 100644 --- a/StevenDimDoors/mod_pocketDim/schematic/CompoundFilter.java +++ b/StevenDimDoors/mod_pocketDim/schematic/CompoundFilter.java @@ -48,11 +48,11 @@ public class CompoundFilter extends SchematicFilter { { for (SchematicFilter filter : filters) { - if (!filter.applyToBlock(index, blocks, metadata)) + if (filter.applyToBlock(index, blocks, metadata)) { - return !filter.terminates(); + return filter.terminates(); } } - return true; + return false; } } diff --git a/StevenDimDoors/mod_pocketDim/schematic/ReplacementFilter.java b/StevenDimDoors/mod_pocketDim/schematic/ReplacementFilter.java index ba99304..e55a7db 100644 --- a/StevenDimDoors/mod_pocketDim/schematic/ReplacementFilter.java +++ b/StevenDimDoors/mod_pocketDim/schematic/ReplacementFilter.java @@ -1,5 +1,6 @@ package StevenDimDoors.mod_pocketDim.schematic; + public class ReplacementFilter extends SchematicFilter { private short targetBlock; diff --git a/StevenDimDoors/mod_pocketDim/schematic/SchematicFilter.java b/StevenDimDoors/mod_pocketDim/schematic/SchematicFilter.java index db3b374..7e80959 100644 --- a/StevenDimDoors/mod_pocketDim/schematic/SchematicFilter.java +++ b/StevenDimDoors/mod_pocketDim/schematic/SchematicFilter.java @@ -21,7 +21,7 @@ public class SchematicFilter { for (int index = 0; index < blocks.length; index++) { - if (!applyToBlock(index, blocks, metadata) && terminates()) + if (applyToBlock(index, blocks, metadata) && terminates()) return false; } From 0c8d012f507dafb94e2028db3d34175c09b5553c Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Tue, 30 Jul 2013 18:27:40 -0400 Subject: [PATCH 7/7] Minor Change Made a minor change to DungeonSchematic so that it replaces foreign mod blocks with the standardized FoR ID on export. Previously it used the Forge-assigned ID, but since that happens after ID standardization, it could cause us to export non-standard IDs. --- StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java b/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java index 35e245b..1eb7d1f 100644 --- a/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java +++ b/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java @@ -144,8 +144,7 @@ public class DungeonSchematic extends Schematic { //Filter out mod blocks except some of our own //This comes after ID standardization because the mod block filter relies on standardized IDs standardizer.addFilter(new ModBlockFilter(MAX_VANILLA_BLOCK_ID, MOD_BLOCK_FILTER_EXCEPTIONS, - (short) properties.FabricBlockID, (byte) 0)); - + STANDARD_FABRIC_OF_REALITY_ID, (byte) 0)); applyFilter(standardizer); }