Created build.gradle
Restructured folder structure for ForgeGradle Signed-off-by: deathrat <deathrat43@gmail.com>
This commit is contained in:
@@ -0,0 +1,495 @@
|
||||
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.mod_pocketDim;
|
||||
|
||||
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 BLOCK_ID_COUNT = 4096;
|
||||
|
||||
//Provides a fast lookup table for whether blocks have orientations
|
||||
private final static boolean[] hasOrientations = new boolean[BLOCK_ID_COUNT];
|
||||
|
||||
static
|
||||
{
|
||||
hasOrientations[Block.dispenser.blockID] = true;
|
||||
hasOrientations[Block.stairsStoneBrick.blockID] = true;
|
||||
hasOrientations[Block.lever.blockID] = true;
|
||||
hasOrientations[Block.stoneButton.blockID] = true;
|
||||
hasOrientations[Block.redstoneRepeaterIdle.blockID] = true;
|
||||
hasOrientations[Block.redstoneRepeaterActive.blockID] = true;
|
||||
hasOrientations[Block.tripWireSource.blockID] = true;
|
||||
hasOrientations[Block.torchWood.blockID] = true;
|
||||
hasOrientations[Block.torchRedstoneIdle.blockID] = true;
|
||||
hasOrientations[Block.torchRedstoneActive.blockID] = true;
|
||||
hasOrientations[Block.doorIron.blockID] = true;
|
||||
hasOrientations[Block.doorWood.blockID] = true;
|
||||
hasOrientations[Block.pistonBase.blockID] = true;
|
||||
hasOrientations[Block.pistonStickyBase.blockID] = true;
|
||||
hasOrientations[Block.pistonExtension.blockID] = true;
|
||||
hasOrientations[Block.redstoneComparatorIdle.blockID] = true;
|
||||
hasOrientations[Block.redstoneComparatorActive.blockID] = true;
|
||||
hasOrientations[Block.signPost.blockID] = true;
|
||||
hasOrientations[Block.signWall.blockID] = true;
|
||||
hasOrientations[Block.skull.blockID] = true;
|
||||
hasOrientations[Block.ladder.blockID] = true;
|
||||
hasOrientations[Block.vine.blockID] = true;
|
||||
hasOrientations[Block.anvil.blockID] = true;
|
||||
hasOrientations[Block.chest.blockID] = true;
|
||||
hasOrientations[Block.chestTrapped.blockID] = true;
|
||||
hasOrientations[Block.hopperBlock.blockID] = true;
|
||||
hasOrientations[Block.stairsNetherBrick.blockID] = true;
|
||||
hasOrientations[Block.stairsCobblestone.blockID] = true;
|
||||
hasOrientations[Block.stairsNetherQuartz.blockID] = true;
|
||||
hasOrientations[Block.stairsSandStone.blockID] = true;
|
||||
hasOrientations[Block.stairsBrick.blockID] = true;
|
||||
hasOrientations[Block.stairsWoodBirch.blockID] = true;
|
||||
hasOrientations[Block.stairsWoodOak.blockID] = true;
|
||||
hasOrientations[Block.stairsWoodJungle.blockID] = true;
|
||||
hasOrientations[Block.stairsWoodSpruce.blockID] = true;
|
||||
hasOrientations[Block.wood.blockID] = true;
|
||||
hasOrientations[Block.blockNetherQuartz.blockID] = true;
|
||||
hasOrientations[Block.railPowered.blockID] = true;
|
||||
hasOrientations[Block.railDetector.blockID] = true;
|
||||
hasOrientations[Block.railActivator.blockID] = true;
|
||||
hasOrientations[Block.rail.blockID] = true;
|
||||
|
||||
hasOrientations[mod_pocketDim.dimensionalDoor.blockID] = true;
|
||||
hasOrientations[mod_pocketDim.warpDoor.blockID] = true;
|
||||
|
||||
}
|
||||
|
||||
public static int transformMetadata(int metadata, int turns, int blockID)
|
||||
{
|
||||
//I changed rotations to reduce the monstrous code we had. It might be
|
||||
//slightly less efficient, but it's easier to maintain for now. ~SenseiKiwi
|
||||
|
||||
//Correct negative turns and get the minimum number of rotations needed
|
||||
turns += 1 << 16;
|
||||
turns %= 4;
|
||||
|
||||
if (hasOrientations[blockID])
|
||||
{
|
||||
while (turns > 0)
|
||||
{
|
||||
metadata = rotateMetadataBy90(metadata, blockID);
|
||||
turns--;
|
||||
}
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private static int rotateMetadataBy90(int metadata, int blockID)
|
||||
{
|
||||
//TODO: Replace this horrible function with something prettier. We promise we will for the next version,
|
||||
//after switching to MC 1.6. PADRE, PLEASE FORGIVE OUR SINS.
|
||||
|
||||
if (blockID == Block.wood.blockID)
|
||||
{
|
||||
if (metadata >= 4 && metadata < 12)
|
||||
{
|
||||
metadata = (metadata % 8) + 4;
|
||||
}
|
||||
}
|
||||
else if (blockID == Block.blockNetherQuartz.blockID)
|
||||
{
|
||||
if (metadata == 3 || metadata == 4)
|
||||
{
|
||||
metadata = (metadata - 2) % 2 + 3;
|
||||
}
|
||||
}
|
||||
else if (blockID == Block.railPowered.blockID || blockID == Block.railDetector.blockID || blockID == Block.railActivator.blockID)
|
||||
{
|
||||
switch (metadata)
|
||||
{
|
||||
//Powered Track/Detector Track/Activator Track (off)
|
||||
case 0:
|
||||
metadata = 1;
|
||||
break;
|
||||
case 1:
|
||||
metadata = 0;
|
||||
break;
|
||||
case 2:
|
||||
metadata = 5;
|
||||
break;
|
||||
case 3:
|
||||
metadata = 4;
|
||||
break;
|
||||
case 4:
|
||||
metadata = 2;
|
||||
break;
|
||||
case 5:
|
||||
metadata = 3;
|
||||
break;
|
||||
|
||||
//Powered Track/Detector Track/Activator Track (on)
|
||||
case 8:
|
||||
metadata = 9;
|
||||
break;
|
||||
case 9:
|
||||
metadata = 8;
|
||||
break;
|
||||
case 10:
|
||||
metadata = 13;
|
||||
break;
|
||||
case 11:
|
||||
metadata = 12;
|
||||
break;
|
||||
case 12:
|
||||
metadata = 10;
|
||||
break;
|
||||
case 13:
|
||||
metadata = 11;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (blockID==Block.rail.blockID)
|
||||
{
|
||||
switch (metadata)
|
||||
{
|
||||
case 0:
|
||||
metadata = 1;
|
||||
break;
|
||||
case 1:
|
||||
metadata = 0;
|
||||
break;
|
||||
case 8:
|
||||
metadata = 9;
|
||||
break;
|
||||
case 9:
|
||||
metadata = 6;
|
||||
break;
|
||||
case 6:
|
||||
metadata = 7;
|
||||
break;
|
||||
case 7:
|
||||
metadata = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else 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 || 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;
|
||||
}
|
||||
|
||||
}
|
||||
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.signWall.blockID)
|
||||
{
|
||||
switch (metadata)
|
||||
{
|
||||
|
||||
case 3:
|
||||
metadata = 4;
|
||||
break;
|
||||
case 2:
|
||||
metadata = 5;
|
||||
break;
|
||||
case 4:
|
||||
metadata = 2;
|
||||
break;
|
||||
case 5:
|
||||
metadata = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (blockID==Block.signPost.blockID)
|
||||
{
|
||||
switch (metadata)
|
||||
{
|
||||
case 0:
|
||||
metadata = 4;
|
||||
break;
|
||||
case 1:
|
||||
metadata = 5;
|
||||
break;
|
||||
case 2:
|
||||
metadata = 6;
|
||||
break;
|
||||
case 3:
|
||||
metadata = 7;
|
||||
break;
|
||||
case 4:
|
||||
metadata = 8;
|
||||
break;
|
||||
case 5:
|
||||
metadata = 9;
|
||||
break;
|
||||
case 6:
|
||||
metadata = 10;
|
||||
break;
|
||||
case 7:
|
||||
metadata = 11;
|
||||
break;
|
||||
case 8:
|
||||
metadata = 12;
|
||||
break;
|
||||
case 9:
|
||||
metadata = 13;
|
||||
break;
|
||||
case 10:
|
||||
metadata = 14;
|
||||
break;
|
||||
case 11:
|
||||
metadata = 15;
|
||||
break;
|
||||
case 12:
|
||||
metadata = 0;
|
||||
break;
|
||||
case 13:
|
||||
metadata = 1;
|
||||
break;
|
||||
case 14:
|
||||
metadata = 2;
|
||||
break;
|
||||
case 15:
|
||||
metadata = 3;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
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 initialize(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;
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package StevenDimDoors.mod_pocketDim.schematic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CompoundFilter extends SchematicFilter {
|
||||
|
||||
private ArrayList<SchematicFilter> filters;
|
||||
|
||||
public CompoundFilter()
|
||||
{
|
||||
super("CompoundFilter");
|
||||
filters = new ArrayList<SchematicFilter>();
|
||||
}
|
||||
|
||||
public void addFilter(SchematicFilter filter)
|
||||
{
|
||||
filters.add(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean initialize(Schematic schematic, short[] blocks, byte[] metadata)
|
||||
{
|
||||
for (SchematicFilter filter : filters)
|
||||
{
|
||||
if (!filter.initialize(schematic, blocks, metadata))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !filters.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean finish()
|
||||
{
|
||||
for (SchematicFilter filter : filters)
|
||||
{
|
||||
if (!filter.finish())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean applyToBlock(int index, short[] blocks, byte[] metadata)
|
||||
{
|
||||
for (SchematicFilter filter : filters)
|
||||
{
|
||||
if (filter.applyToBlock(index, blocks, metadata))
|
||||
{
|
||||
return filter.terminates();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,435 @@
|
||||
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.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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
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 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)];
|
||||
}
|
||||
|
||||
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(String schematicPath) throws FileNotFoundException, InvalidSchematicException
|
||||
{
|
||||
return readFromFile(new File(schematicPath));
|
||||
}
|
||||
|
||||
public static Schematic readFromFile(File schematicFile) throws FileNotFoundException, InvalidSchematicException
|
||||
{
|
||||
// TODO: fix resource leaks here
|
||||
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);
|
||||
}
|
||||
|
||||
public 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 && hasExtendedBlockIDs)
|
||||
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] & 0xFF));
|
||||
blocks[index + 1] = (short) (((highBits[index >> 1] & 0xF0) << 4) + (lowBits[index + 1] & 0xFF));
|
||||
}
|
||||
if (index < volume)
|
||||
{
|
||||
blocks[index] = lowBits[index >> 1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Copy the blockIDs
|
||||
for (int index = 0; index < volume; index++)
|
||||
{
|
||||
blocks[index] = (short) (lowBits[index] & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
//Get the list of tile entities
|
||||
tileEntities = schematicTag.getTagList("TileEntities");
|
||||
|
||||
Schematic result = new Schematic(width, height, length, blocks, metadata, tileEntities);
|
||||
return result;
|
||||
}
|
||||
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)
|
||||
{
|
||||
//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);
|
||||
}
|
||||
for (index = 0; index < blocks.length; index++)
|
||||
{
|
||||
lowBits[index] = (byte) (blocks[index] & 0xFF);
|
||||
}
|
||||
return hasHighBits;
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT()
|
||||
{
|
||||
return writeToNBT(true);
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
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[] lowBits = new byte[blocks.length];
|
||||
byte[] highBits = new byte[(blocks.length >> 1) + (blocks.length & 1)];
|
||||
boolean hasExtendedIDs = encodeBlockIDs(blocks, lowBits, highBits);
|
||||
|
||||
schematicTag.setByteArray("Blocks", lowBits);
|
||||
schematicTag.setByteArray("Data", metadata);
|
||||
|
||||
if (hasExtendedIDs)
|
||||
{
|
||||
schematicTag.setByteArray("AddBlocks", highBits);
|
||||
}
|
||||
|
||||
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", 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();
|
||||
}
|
||||
|
||||
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.
|
||||
//It's not worth the trouble in this case.
|
||||
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++)
|
||||
{
|
||||
//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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
//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));
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
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 = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean initialize(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];
|
||||
tileEntities = new NBTTagList();
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package StevenDimDoors.mod_pocketDim.schematic;
|
||||
|
||||
import StevenDimDoors.mod_pocketDim.Point3D;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class WorldOperation {
|
||||
|
||||
private String name;
|
||||
|
||||
public WorldOperation(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected boolean initialize(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, 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))
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user