Merge pull request #2 from Waterpicker/1.8.9

I might gone overboard with how deep I went this time.
This commit is contained in:
Zixiken 2016-06-24 12:15:42 -04:00 committed by GitHub
commit 3c94804241
37 changed files with 859 additions and 1541 deletions

View file

@ -175,11 +175,11 @@ public class BlockRift extends Block implements ITileEntityProvider {
private void destroyNearbyBlocks(World world, int x, int y, int z, Random random) private void destroyNearbyBlocks(World world, int x, int y, int z, Random random)
{ {
// Find reachable blocks that are vulnerable to rift damage (ignoring air, of course) // Find reachable blocks that are vulnerable to rift damage (ignoring air, of course)
ArrayList<Point3D> targets = findReachableBlocks(world, x, y, z, BLOCK_DESTRUCTION_RANGE, false); ArrayList<BlockPos> targets = findReachableBlocks(world, x, y, z, BLOCK_DESTRUCTION_RANGE, false);
// For each block, randomly decide whether to destroy it. // For each block, randomly decide whether to destroy it.
// The randomness makes it so the destroyed area appears "noisy" if the rift is exposed to a large surface. // The randomness makes it so the destroyed area appears "noisy" if the rift is exposed to a large surface.
for (Point3D target : targets) for (BlockPos target : targets)
{ {
if (random.nextInt(MAX_BLOCK_DESTRUCTION_CHANCE) < BLOCK_DESTRUCTION_CHANCE) if (random.nextInt(MAX_BLOCK_DESTRUCTION_CHANCE) < BLOCK_DESTRUCTION_CHANCE)
{ {
@ -189,20 +189,20 @@ public class BlockRift extends Block implements ITileEntityProvider {
} }
} }
private ArrayList<Point3D> findReachableBlocks(World world, int x, int y, int z, int range, boolean includeAir) private ArrayList<BlockPos> findReachableBlocks(World world, int x, int y, int z, int range, boolean includeAir)
{ {
int searchVolume = (int) Math.pow(2 * range + 1, 3); int searchVolume = (int) Math.pow(2 * range + 1, 3);
HashMap<Point3D, Integer> pointDistances = new HashMap<Point3D, Integer>(searchVolume); HashMap<BlockPos, Integer> pointDistances = new HashMap<BlockPos, Integer>(searchVolume);
Queue<Point3D> points = new LinkedList<Point3D>(); Queue<BlockPos> points = new LinkedList<BlockPos>();
ArrayList<Point3D> targets = new ArrayList<Point3D>(); ArrayList<BlockPos> targets = new ArrayList<BlockPos>();
// Perform a breadth-first search outwards from the point at which the rift is located. // Perform a breadth-first search outwards from the point at which the rift is located.
// Record the distances of the points we visit to stop the search at its maximum range. // Record the distances of the points we visit to stop the search at its maximum range.
pointDistances.put(new Point3D(x, y, z), 0); pointDistances.put(new BlockPos(x, y, z), 0);
addAdjacentBlocks(x, y, z, 0, pointDistances, points); addAdjacentBlocks(x, y, z, 0, pointDistances, points);
while (!points.isEmpty()) while (!points.isEmpty())
{ {
Point3D current = points.remove(); BlockPos current = points.remove();
int distance = pointDistances.get(current); int distance = pointDistances.get(current);
// If the current block is air, continue searching. Otherwise, add the block to our list. // If the current block is air, continue searching. Otherwise, add the block to our list.
@ -241,15 +241,15 @@ public class BlockRift extends Block implements ITileEntityProvider {
} }
} }
private static void addAdjacentBlocks(int x, int y, int z, int distance, HashMap<Point3D, Integer> pointDistances, Queue<Point3D> points) private static void addAdjacentBlocks(int x, int y, int z, int distance, HashMap<BlockPos, Integer> pointDistances, Queue<BlockPos> points)
{ {
Point3D[] neighbors = new Point3D[] { BlockPos[] neighbors = new BlockPos[] {
new Point3D(x - 1, y, z), new BlockPos(x - 1, y, z),
new Point3D(x + 1, y, z), new BlockPos(x + 1, y, z),
new Point3D(x, y - 1, z), new BlockPos(x, y - 1, z),
new Point3D(x, y + 1, z), new BlockPos(x, y + 1, z),
new Point3D(x, y, z - 1), new BlockPos(x, y, z - 1),
new Point3D(x, y, z + 1) new BlockPos(x, y, z + 1)
}; };
for (int index = 0; index < neighbors.length; index++) for (int index = 0; index < neighbors.length; index++)
{ {
@ -268,13 +268,13 @@ public class BlockRift extends Block implements ITileEntityProvider {
Point4D source = parent.source(); Point4D source = parent.source();
// Find reachable blocks that are vulnerable to rift damage and include air // Find reachable blocks that are vulnerable to rift damage and include air
ArrayList<Point3D> targets = findReachableBlocks(world, source.getX(), source.getY(), source.getZ(), ArrayList<BlockPos> targets = findReachableBlocks(world, source.getX(), source.getY(), source.getZ(),
RIFT_SPREAD_RANGE, true); RIFT_SPREAD_RANGE, true);
if (!targets.isEmpty()) if (!targets.isEmpty())
{ {
// Choose randomly from among the possible locations where we can spawn a new rift // Choose randomly from among the possible locations where we can spawn a new rift
Point3D target = targets.get( random.nextInt(targets.size()) ); BlockPos target = targets.get( random.nextInt(targets.size()) );
x = target.getX(); x = target.getX();
y = target.getY(); y = target.getY();
z = target.getZ(); z = target.getZ();
@ -310,7 +310,7 @@ public class BlockRift extends Block implements ITileEntityProvider {
{ {
ArrayList<Point3D> targets=findReachableBlocks(world, x, y, z, 2, false); ArrayList<BlockPos> targets=findReachableBlocks(world, x, y, z, 2, false);
TileEntityRift tile = (TileEntityRift)world.getTileEntity(x, y, z); TileEntityRift tile = (TileEntityRift)world.getTileEntity(x, y, z);

View file

@ -4,8 +4,10 @@ import com.zixiken.dimdoors.core.DimLink;
import com.zixiken.dimdoors.core.LinkType; import com.zixiken.dimdoors.core.LinkType;
import com.zixiken.dimdoors.core.PocketManager; import com.zixiken.dimdoors.core.PocketManager;
import com.zixiken.dimdoors.DimDoors; import com.zixiken.dimdoors.DimDoors;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.material.Material; import net.minecraft.block.material.Material;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import com.zixiken.dimdoors.core.NewDimData; import com.zixiken.dimdoors.core.NewDimData;
@ -19,15 +21,12 @@ public class WarpDoor extends BaseDimDoor {
} }
@Override @Override
public void placeLink(World world, int x, int y, int z) public void placeLink(World world, BlockPos pos) {
{ if (!world.isRemote && world.getBlockState(pos.down()) == this) {
if (!world.isRemote && world.getBlock(x, y - 1, z) == this)
{
NewDimData dimension = PocketManager.createDimensionData(world); NewDimData dimension = PocketManager.createDimensionData(world);
DimLink link = dimension.getLink(x, y, z); DimLink link = dimension.getLink(pos);
if (link == null && dimension.isPocketDimension()) if (link == null && dimension.isPocketDimension()) {
{ dimension.createLink(pos, LinkType.SAFE_EXIT,world. getBlockState(pos.down()).getValue(BlockDoor.FACING));
dimension.createLink(x, y, z, LinkType.SAFE_EXIT,world.getBlockMetadata(x, y - 1, z));
} }
} }
} }

View file

@ -42,16 +42,12 @@ public class DDLock
/** /**
* see if we could unlock this door if it where locked. * see if we could unlock this door if it where locked.
* @param link
* @param itemStack * @param itemStack
* @return * @return
*/ */
public boolean doesKeyUnlock(ItemStack itemStack) public boolean doesKeyUnlock(ItemStack itemStack) {
{ for(int key :getKeys(itemStack)) {
for(int key :getKeys(itemStack)) if(this.lockKey == key) {
{
if(this.lockKey == key)
{
return true; return true;
} }
} }
@ -60,11 +56,10 @@ public class DDLock
/** /**
* Tries to open this lock * Tries to open this lock
* @param item * @param itemStack
* @return * @return
*/ */
public boolean tryToOpen(ItemStack itemStack) public boolean tryToOpen(ItemStack itemStack) {
{
return (!this.lockState)||this.doesKeyUnlock(itemStack); return (!this.lockState)||this.doesKeyUnlock(itemStack);
} }
@ -78,10 +73,8 @@ public class DDLock
* gets all the keys stored on a single key item * gets all the keys stored on a single key item
* @return * @return
*/ */
public static int[] getKeys(ItemStack itemStack) public static int[] getKeys(ItemStack itemStack) {
{ if (!itemStack.hasTagCompound()) {
if (!itemStack.hasTagCompound())
{
initNBTTags(itemStack); initNBTTags(itemStack);
} }
return itemStack.getTagCompound().getIntArray("DDKeys"); return itemStack.getTagCompound().getIntArray("DDKeys");
@ -92,8 +85,7 @@ public class DDLock
* @return * @return
* @return * @return
*/ */
public static void addKeys(ItemStack itemStack, int[] keysToAdd) public static void addKeys(ItemStack itemStack, int[] keysToAdd) {
{
int[] oldKeys = DDLock.getKeys(itemStack); int[] oldKeys = DDLock.getKeys(itemStack);
int[] newKeys = new int[keysToAdd.length+oldKeys.length]; int[] newKeys = new int[keysToAdd.length+oldKeys.length];
System.arraycopy(oldKeys, 0, newKeys, 0, oldKeys.length); System.arraycopy(oldKeys, 0, newKeys, 0, oldKeys.length);
@ -107,10 +99,8 @@ public class DDLock
* @return * @return
* @return * @return
*/ */
public static void setKeys(ItemStack itemStack, int[] keys) public static void setKeys(ItemStack itemStack, int[] keys) {
{ if (!itemStack.hasTagCompound()) {
if (!itemStack.hasTagCompound())
{
initNBTTags(itemStack); initNBTTags(itemStack);
} }
NBTTagCompound tag = itemStack.getTagCompound(); NBTTagCompound tag = itemStack.getTagCompound();
@ -122,8 +112,7 @@ public class DDLock
* Gives the key a new NBTTag * Gives the key a new NBTTag
* @param itemStack * @param itemStack
*/ */
public static void initNBTTags(ItemStack itemStack) public static void initNBTTags(ItemStack itemStack) {
{
itemStack.setTagCompound(new NBTTagCompound()); itemStack.setTagCompound(new NBTTagCompound());
NBTTagCompound tag = itemStack.getTagCompound(); NBTTagCompound tag = itemStack.getTagCompound();
tag.setIntArray("DDKeys", new int[0]); tag.setIntArray("DDKeys", new int[0]);
@ -144,20 +133,16 @@ public class DDLock
return false; return false;
} }
public static boolean isItemKey(ItemStack key) public static boolean isItemKey(ItemStack key) {
{
return key.getItem() instanceof ItemDDKey; return key.getItem() instanceof ItemDDKey;
} }
protected static DDLock generateLockKeyPair(ItemStack itemStack, int lockKey2) protected static DDLock generateLockKeyPair(ItemStack itemStack, int lockKey2) {
{
itemStack.getTagCompound().setBoolean("HasCreatedLock", true); itemStack.getTagCompound().setBoolean("HasCreatedLock", true);
DDLock.setKeys(itemStack, new int[]{lockKey2}); DDLock.setKeys(itemStack, new int[]{lockKey2});
return new DDLock(true, lockKey2); return new DDLock(true, lockKey2);
} }
} }

View file

@ -17,6 +17,8 @@ import com.zixiken.dimdoors.world.PocketBuilder;
import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.gameevent.PlayerEvent; import cpw.mods.fml.common.gameevent.PlayerEvent;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityList;
import net.minecraft.entity.item.EntityMinecart; import net.minecraft.entity.item.EntityMinecart;
@ -30,6 +32,8 @@ import net.minecraft.network.play.server.S1DPacketEntityEffect;
import net.minecraft.network.play.server.S1FPacketSetExperience; import net.minecraft.network.play.server.S1FPacketSetExperience;
import net.minecraft.potion.PotionEffect; import net.minecraft.potion.PotionEffect;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.MathHelper; import net.minecraft.util.MathHelper;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.WorldServer; import net.minecraft.world.WorldServer;
@ -37,8 +41,7 @@ import net.minecraftforge.common.DimensionManager;
import com.zixiken.dimdoors.watcher.ClientDimData; import com.zixiken.dimdoors.watcher.ClientDimData;
import cpw.mods.fml.common.registry.GameRegistry; import cpw.mods.fml.common.registry.GameRegistry;
public class DDTeleporter public class DDTeleporter {
{
private static final Random random = new Random(); private static final Random random = new Random();
private static final int NETHER_DIMENSION_ID = -1; private static final int NETHER_DIMENSION_ID = -1;
private static final int OVERWORLD_DIMENSION_ID = 0; private static final int OVERWORLD_DIMENSION_ID = 0;
@ -59,50 +62,45 @@ public class DDTeleporter
/** /**
* Checks if the destination supplied is safe (i.e. filled by any replaceable or non-opaque blocks) * Checks if the destination supplied is safe (i.e. filled by any replaceable or non-opaque blocks)
*/ */
private static boolean checkDestination(WorldServer world, Point4D destination, int orientation) private static boolean checkDestination(WorldServer world, Point4D destination, EnumFacing orientation) {
{
int x = destination.getX(); int x = destination.getX();
int y = destination.getY(); int y = destination.getY();
int z = destination.getZ(); int z = destination.getZ();
Block blockTop; Block blockTop;
Block blockBottom; Block blockBottom;
Point3D point; BlockPos point;
switch (orientation) switch (orientation) {
{ case SOUTH:
case 0: point = new BlockPos(x - 1, y - 1, z);
point = new Point3D(x - 1, y - 1, z);
break; break;
case 1: case WEST:
point = new Point3D(x, y - 1, z - 1); point = new BlockPos(x, y - 1, z - 1);
break; break;
case 2: case NORTH:
point = new Point3D(x + 1, y - 1, z); point = new BlockPos(x + 1, y - 1, z);
break; break;
case 3: case EAST:
point = new Point3D(x, y - 1, z + 1); point = new BlockPos(x, y - 1, z + 1);
break; break;
default: default:
point = new Point3D(x, y - 1, z); point = new BlockPos(x, y - 1, z);
break; break;
} }
blockBottom = world.getBlock(point.getX(), point.getY(), point.getZ());
blockTop = world.getBlock(point.getX(), point.getY() + 1, point.getZ());
if (blockBottom != null) blockBottom = world.getBlockState(point).getBlock();
{ blockTop = world.getBlockState(point.up()).getBlock();
if (!blockBottom.isReplaceable(world, point.getX(), point.getY(), point.getZ()) && world.isBlockNormalCubeDefault(point.getX(), point.getY(), point.getZ(), false))
{ if (blockBottom != null) {
return false; if (!blockBottom.isReplaceable(world, point) && world.isBlockNormalCube(point, false)) {
} return false;
} }
if (blockTop != null) } if (blockTop != null) {
{ if (!blockTop.isReplaceable(world, point.up())) {
if (!blockTop.isReplaceable(world, point.getX(), point.getY() + 1, point.getZ()))
{
return false; return false;
} }
} }
return true; return true;
} }
@ -112,16 +110,16 @@ public class DDTeleporter
int y = destination.getY(); int y = destination.getY();
int z = destination.getZ(); int z = destination.getZ();
int orientation; EnumFacing orientation;
if (checkOrientation) if (checkOrientation)
{ {
orientation = getDestinationOrientation(destination, properties); orientation = getDestinationOrientation(destination, properties);
entity.rotationYaw = (orientation * 90) + 90; entity.rotationYaw = (orientation.getIndex() * 90) + 90;
} }
else else
{ {
// Teleport the entity to the precise destination point // Teleport the entity to the precise destination point
orientation = -1; orientation = EnumFacing.SOUTH;
} }
if (entity instanceof EntityPlayer) if (entity instanceof EntityPlayer)
@ -148,8 +146,7 @@ public class DDTeleporter
break; break;
} }
} }
else else {
{
player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5); player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5);
} }
} }
@ -217,29 +214,25 @@ public class DDTeleporter
entity.setPosition(x, y, z); entity.setPosition(x, y, z);
} }
private static int getDestinationOrientation(Point4D door, DDProperties properties) private static EnumFacing getDestinationOrientation(Point4D door, DDProperties properties) {
{
World world = DimensionManager.getWorld(door.getDimension()); World world = DimensionManager.getWorld(door.getDimension());
if (world == null) if (world == null) {
{
throw new IllegalStateException("The destination world should be loaded!"); throw new IllegalStateException("The destination world should be loaded!");
} }
//Check if the block below that point is actually a door //Check if the block below that point is actually a door
Block block = world.getBlock(door.getX(), door.getY() - 1, door.getZ()); IBlockState block = world.getBlockState(door.toBlockPos().down());
if (block==null || !(block instanceof IDimDoor)) if (block==null || !(block instanceof IDimDoor)) {
{
//Return the pocket's orientation instead //Return the pocket's orientation instead
return PocketManager.createDimensionData(world).orientation(); return PocketManager.createDimensionData(world).orientation();
} }
//Return the orientation portion of its metadata //Return the orientation portion of its metadata
return world.getBlockMetadata(door.getX(), door.getY() - 1, door.getZ()) & 3; return world.getBlockState(door.toBlockPos().down()).getValue(BlockDoor.FACING);
} }
public static Entity teleportEntity(Entity entity, Point4D destination, boolean checkOrientation) public static Entity teleportEntity(Entity entity, Point4D destination, boolean checkOrientation) {
{
if (entity == null) if (entity == null)
{ {
throw new IllegalArgumentException("entity cannot be null."); throw new IllegalArgumentException("entity cannot be null.");
@ -390,6 +383,7 @@ public class DDTeleporter
// Let's try doing this down here in case this is what's killing NEI. // Let's try doing this down here in case this is what's killing NEI.
FMLCommonHandler.instance().firePlayerChangedDimensionEvent((EntityPlayer) entity, oldWorld.provider.dimensionId, newWorld.provider.dimensionId); FMLCommonHandler.instance().firePlayerChangedDimensionEvent((EntityPlayer) entity, oldWorld.provider.dimensionId, newWorld.provider.dimensionId);
} }
DDTeleporter.placeInPortal(entity, newWorld, destination, properties, checkOrientation); DDTeleporter.placeInPortal(entity, newWorld, destination, properties, checkOrientation);
return entity; return entity;
} }
@ -591,7 +585,7 @@ public class DDTeleporter
return false; return false;
} }
Point3D destination = yCoordHelper.findDropPoint(world, source.getX(), source.getY() + 1, source.getZ()); BlockPos destination = yCoordHelper.findDropPoint(world, source.getX(), source.getY() + 1, source.getZ());
if (destination != null) if (destination != null)
{ {
current.root().setLinkDestination(link, destination.getX(), destination.getY(), destination.getZ()); current.root().setLinkDestination(link, destination.getX(), destination.getY(), destination.getZ());
@ -707,9 +701,9 @@ public class DDTeleporter
} }
int startY = source.getY() - 2; int startY = source.getY() - 2;
Point3D destination; BlockPos destination;
Point3D locationUp = yCoordHelper.findSafeCubeUp(world, source.getX(), startY, source.getZ()); BlockPos locationUp = yCoordHelper.findSafeCubeUp(world, source.getX(), startY, source.getZ());
Point3D locationDown = yCoordHelper.findSafeCubeDown(world, source.getX(), startY, source.getZ()); BlockPos locationDown = yCoordHelper.findSafeCubeDown(world, source.getX(), startY, source.getZ());
if (locationUp == null) if (locationUp == null)
{ {

View file

@ -3,23 +3,22 @@ package com.zixiken.dimdoors.core;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.ChunkCoordIntPair;
import com.zixiken.dimdoors.util.Point4D; import com.zixiken.dimdoors.util.Point4D;
public abstract class DimLink public abstract class DimLink
{ {
protected Point4D point; protected Point4D point;
protected int orientation; protected EnumFacing orientation;
protected DDLock lock; protected DDLock lock;
protected DimLink parent; protected DimLink parent;
protected LinkTail tail; protected LinkTail tail;
protected List<DimLink> children; protected List<DimLink> children;
protected DimLink(Point4D point, int orientation, DDLock lock, DimLink parent) protected DimLink(Point4D point, EnumFacing orientation, DDLock lock, DimLink parent) {
{
if (parent.point.getDimension() != point.getDimension()) if (parent.point.getDimension() != point.getDimension()) {
{
// Ban having children in other dimensions to avoid serialization issues with cross-dimensional tails // Ban having children in other dimensions to avoid serialization issues with cross-dimensional tails
throw new IllegalArgumentException("source and parent.source must have the same dimension."); throw new IllegalArgumentException("source and parent.source must have the same dimension.");
} }
@ -32,8 +31,7 @@ public abstract class DimLink
parent.children.add(this); parent.children.add(this);
} }
protected DimLink(Point4D point, int orientation, DDLock lock, LinkType linkType) protected DimLink(Point4D point, EnumFacing orientation, DDLock lock, LinkType linkType) {
{
/**This really cant happen anymore, I guess. /**This really cant happen anymore, I guess.
* *
if ((linkType < LinkTypes.ENUM_MIN || linkType > LinkTypes.ENUM_MAX) && linkType != LinkTypes.CLIENT_SIDE) if ((linkType < LinkTypes.ENUM_MIN || linkType > LinkTypes.ENUM_MAX) && linkType != LinkTypes.CLIENT_SIDE)
@ -50,23 +48,19 @@ public abstract class DimLink
this.children = new LinkedList<DimLink>(); this.children = new LinkedList<DimLink>();
} }
public Point4D source() public Point4D source() {
{
return point; return point;
} }
public void clear() public void clear() {
{
//Release children //Release children
for (DimLink child : children) for (DimLink child : children) {
{
child.parent = null; child.parent = null;
} }
children.clear(); children.clear();
//Release parent //Release parent
if (parent != null) if (parent != null) {
{
parent.children.remove(this); parent.children.remove(this);
} }
@ -75,48 +69,39 @@ public abstract class DimLink
tail = new LinkTail(LinkType.NORMAL, null); tail = new LinkTail(LinkType.NORMAL, null);
} }
public int orientation() public EnumFacing orientation() {
{
return orientation; return orientation;
} }
public Point4D destination() public Point4D destination() {
{
return tail.getDestination(); return tail.getDestination();
} }
public int getDestinationOrientation() public EnumFacing getDestinationOrientation() {
{
DimLink destinationLink = PocketManager.getLink(tail.getDestination()); DimLink destinationLink = PocketManager.getLink(tail.getDestination());
if (destinationLink != null) if (destinationLink != null) {
{
return destinationLink.orientation(); return destinationLink.orientation();
} }
return (orientation + 2) % 4; return orientation.rotateY().rotateY();
} }
public boolean hasDestination() public boolean hasDestination() {
{ return tail.getDestination() != null;
return (tail.getDestination() != null);
} }
public Iterable<DimLink> children() public Iterable<DimLink> children() {
{
return children; return children;
} }
public int childCount() public int childCount() {
{
return children.size(); return children.size();
} }
public DimLink parent() public DimLink parent() {
{
return parent; return parent;
} }
public LinkType linkType() public LinkType linkType() {
{
return tail.getLinkType(); return tail.getLinkType();
} }
@ -125,8 +110,7 @@ public abstract class DimLink
* Tries to open this lock. Returns true if the lock is open or if the key can open it * Tries to open this lock. Returns true if the lock is open or if the key can open it
* @return * @return
*/ */
public boolean tryToOpen(ItemStack item) public boolean tryToOpen(ItemStack item) {
{
return lock.tryToOpen(item); return lock.tryToOpen(item);
} }
@ -134,8 +118,7 @@ public abstract class DimLink
* Tests if the given key item fits this lock * Tests if the given key item fits this lock
* @return * @return
*/ */
public boolean doesKeyUnlock(ItemStack item) public boolean doesKeyUnlock(ItemStack item) {
{
return lock.doesKeyUnlock(item); return lock.doesKeyUnlock(item);
} }
@ -143,8 +126,7 @@ public abstract class DimLink
* test if there is a lock, regardless if it is locked or not. * test if there is a lock, regardless if it is locked or not.
* @return * @return
*/ */
public boolean hasLock() public boolean hasLock() {
{
return this.lock!=null; return this.lock!=null;
} }
@ -152,8 +134,7 @@ public abstract class DimLink
* Tests if the lock is open or not * Tests if the lock is open or not
* *
*/ */
public boolean getLockState() public boolean getLockState() {
{
return this.hasLock()&&this.lock.getLockState(); return this.hasLock()&&this.lock.getLockState();
} }
@ -161,19 +142,16 @@ public abstract class DimLink
* gets the actual lock object * gets the actual lock object
* @return * @return
*/ */
public DDLock getLock() public DDLock getLock() {
{
return this.lock; return this.lock;
} }
public ChunkCoordIntPair getChunkCoordinates() public ChunkCoordIntPair getChunkCoordinates() {
{
return new ChunkCoordIntPair(point.getX() >> 4, point.getZ() >> 4); return new ChunkCoordIntPair(point.getX() >> 4, point.getZ() >> 4);
} }
@Override @Override
public String toString() public String toString() {
{
return point + " -> " + (hasDestination() ? destination() : "()"); return point + " -> " + (hasDestination() ? destination() : "()");
} }
} }

View file

@ -17,6 +17,8 @@ import com.zixiken.dimdoors.dungeon.pack.DungeonPack;
import com.zixiken.dimdoors.util.Point4D; import com.zixiken.dimdoors.util.Point4D;
import com.zixiken.dimdoors.watcher.IUpdateWatcher; import com.zixiken.dimdoors.watcher.IUpdateWatcher;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.world.World; import net.minecraft.world.World;
import com.zixiken.dimdoors.saving.IPackable; import com.zixiken.dimdoors.saving.IPackable;
@ -25,52 +27,39 @@ import com.zixiken.dimdoors.saving.PackedDungeonData;
import com.zixiken.dimdoors.saving.PackedLinkData; import com.zixiken.dimdoors.saving.PackedLinkData;
import com.zixiken.dimdoors.saving.PackedLinkTail; import com.zixiken.dimdoors.saving.PackedLinkTail;
public abstract class NewDimData implements IPackable<PackedDimData> public abstract class NewDimData implements IPackable<PackedDimData> {
{ private static class InnerDimLink extends DimLink {
private static class InnerDimLink extends DimLink public InnerDimLink(Point4D source, DimLink parent, EnumFacing orientation, DDLock lock) {
{
public InnerDimLink(Point4D source, DimLink parent, int orientation, DDLock lock)
{
super(source, orientation, lock, parent); super(source, orientation, lock, parent);
} }
public InnerDimLink(Point4D source, LinkType linkType, int orientation, DDLock lock) public InnerDimLink(Point4D source, LinkType linkType, EnumFacing orientation, DDLock lock) {
{
super(source, orientation, lock, linkType); super(source, orientation, lock, linkType);
} }
public void setDestination(int x, int y, int z, NewDimData dimension) public void setDestination(BlockPos pos, NewDimData dimension) {
{ tail.setDestination(new Point4D(pos, dimension.id()));
tail.setDestination(new Point4D(x, y, z, dimension.id()));
} }
public boolean overwrite(InnerDimLink nextParent,int orientation) public boolean overwrite(InnerDimLink nextParent, EnumFacing orientation) {
{ if (nextParent == null) {
if (nextParent == null)
{
throw new IllegalArgumentException("nextParent cannot be null."); throw new IllegalArgumentException("nextParent cannot be null.");
} } if (this == nextParent) {
if (this == nextParent)
{
//Ignore this request silently //Ignore this request silently
return false; return false;
} } if (nextParent.point.getDimension() != point.getDimension()) {
if (nextParent.point.getDimension() != point.getDimension())
{
// Ban having children in other dimensions to avoid serialization issues with cross-dimensional tails // Ban having children in other dimensions to avoid serialization issues with cross-dimensional tails
throw new IllegalArgumentException("source and parent.source must have the same dimension."); throw new IllegalArgumentException("source and parent.source must have the same dimension.");
} }
//Release children //Release children
for (DimLink child : children) for (DimLink child : children) {
{
((InnerDimLink) child).parent = null; ((InnerDimLink) child).parent = null;
} }
children.clear(); children.clear();
//Release parent //Release parent
if (parent != null) if (parent != null) {
{
parent.children.remove(this); parent.children.remove(this);
} }
@ -82,18 +71,15 @@ public abstract class NewDimData implements IPackable<PackedDimData>
return true; return true;
} }
public void overwrite(LinkType linkType, int orientation) public void overwrite(LinkType linkType, EnumFacing orientation) {
{
//Release children //Release children
for (DimLink child : children) for (DimLink child : children) {
{
((InnerDimLink) child).parent = null; ((InnerDimLink) child).parent = null;
} }
children.clear(); children.clear();
//Release parent //Release parent
if (parent != null) if (parent != null) {
{
parent.children.remove(this); parent.children.remove(this);
} }
@ -108,8 +94,7 @@ public abstract class NewDimData implements IPackable<PackedDimData>
* only use this on the client to update errything * only use this on the client to update errything
* @param lock * @param lock
*/ */
public void setLock(DDLock lock) public void setLock(DDLock lock) {
{
this.lock = lock; this.lock = lock;
} }
@ -118,20 +103,16 @@ public abstract class NewDimData implements IPackable<PackedDimData>
* @param itemStack * @param itemStack
* @return * @return
*/ */
public boolean createLock(ItemStack itemStack, int lockKey) public boolean createLock(ItemStack itemStack, int lockKey) {
{ if(this.hasLock()||DDLock.hasCreatedLock(itemStack)) {
if(this.hasLock()||DDLock.hasCreatedLock(itemStack))
{
return false; return false;
} }
this.lock = DDLock.generateLockKeyPair(itemStack, lockKey); this.lock = DDLock.generateLockKeyPair(itemStack, lockKey);
return true; return true;
} }
public void removeLock(ItemStack itemStack, InnerDimLink link) public void removeLock(ItemStack itemStack, InnerDimLink link) {
{ if(link.doesKeyUnlock(itemStack)) {
if(link.doesKeyUnlock(itemStack))
{
link.lock = null; link.lock = null;
} }
} }
@ -153,7 +134,7 @@ public abstract class NewDimData implements IPackable<PackedDimData>
protected NewDimData root; protected NewDimData root;
protected List<NewDimData> children; protected List<NewDimData> children;
protected Point4D origin; protected Point4D origin;
protected int orientation; protected EnumFacing orientation;
protected DungeonData dungeon; protected DungeonData dungeon;
protected boolean modified; protected boolean modified;
public IUpdateWatcher<ClientLinkData> linkWatcher; public IUpdateWatcher<ClientLinkData> linkWatcher;
@ -162,10 +143,8 @@ public abstract class NewDimData implements IPackable<PackedDimData>
// Don't write this field to a file - it should be recreated on startup // Don't write this field to a file - it should be recreated on startup
private Map<ChunkCoordIntPair, List<InnerDimLink>> chunkMapping; private Map<ChunkCoordIntPair, List<InnerDimLink>> chunkMapping;
protected NewDimData(int id, NewDimData parent, DimensionType type, IUpdateWatcher<ClientLinkData> linkWatcher) protected NewDimData(int id, NewDimData parent, DimensionType type, IUpdateWatcher<ClientLinkData> linkWatcher) {
{ if (type != DimensionType.ROOT && (parent == null)) {
if (type != DimensionType.ROOT && (parent == null))
{
throw new NullPointerException("Dimensions can be pocket dimensions if and only if they have a parent dimension."); throw new NullPointerException("Dimensions can be pocket dimensions if and only if they have a parent dimension.");
} }
@ -177,7 +156,7 @@ public abstract class NewDimData implements IPackable<PackedDimData>
this.packDepth = 0; this.packDepth = 0;
this.type = type; this.type = type;
this.isFilled = false; this.isFilled = false;
this.orientation = 0; this.orientation = EnumFacing.SOUTH;
this.origin = null; this.origin = null;
this.dungeon = null; this.dungeon = null;
this.linkWatcher = linkWatcher; this.linkWatcher = linkWatcher;
@ -185,26 +164,21 @@ public abstract class NewDimData implements IPackable<PackedDimData>
this.modified = true; this.modified = true;
//Register with parent //Register with parent
if (parent != null) if (parent != null) {
{
//We don't need to raise an update event for adding a child because the child's creation will be signaled. //We don't need to raise an update event for adding a child because the child's creation will be signaled.
this.root = parent.root; this.root = parent.root;
this.depth = parent.depth + 1; this.depth = parent.depth + 1;
parent.children.add(this); parent.children.add(this);
parent.modified = true; parent.modified = true;
} } else {
else
{
this.root = this; this.root = this;
this.depth = 0; this.depth = 0;
} }
} }
protected NewDimData(int id, NewDimData root, DimensionType type) protected NewDimData(int id, NewDimData root, DimensionType type) {
{
// This constructor is meant for client-side code only // This constructor is meant for client-side code only
if (root == null) if (root == null) {
{
throw new IllegalArgumentException("root cannot be null."); throw new IllegalArgumentException("root cannot be null.");
} }
@ -216,7 +190,7 @@ public abstract class NewDimData implements IPackable<PackedDimData>
this.packDepth = 0; this.packDepth = 0;
this.type = type; this.type = type;
this.isFilled = false; this.isFilled = false;
this.orientation = 0; this.orientation = EnumFacing.SOUTH;
this.origin = null; this.origin = null;
this.dungeon = null; this.dungeon = null;
this.linkWatcher = null; this.linkWatcher = null;
@ -226,11 +200,9 @@ public abstract class NewDimData implements IPackable<PackedDimData>
} }
public DimLink findNearestRift(World world, int range, int x, int y, int z) public DimLink findNearestRift(World world, int range, BlockPos pos) {
{
// Sanity check... // Sanity check...
if (world.provider.dimensionId != id) if (world.provider.getDimensionId() != id) {
{
throw new IllegalArgumentException("Attempted to search for links in a World instance for a different dimension!"); throw new IllegalArgumentException("Attempted to search for links in a World instance for a different dimension!");
} }
@ -244,18 +216,13 @@ public abstract class NewDimData implements IPackable<PackedDimData>
int minDistance = Integer.MAX_VALUE; int minDistance = Integer.MAX_VALUE;
DDProperties properties = DDProperties.instance(); DDProperties properties = DDProperties.instance();
for (i = -range; i <= range; i++) for (i = -range; i <= range; i++) {
{ for (j = -range; j <= range; j++) {
for (j = -range; j <= range; j++) for (k = -range; k <= range; k++) {
{
for (k = -range; k <= range; k++)
{
distance = getAbsoluteSum(i, j, k); distance = getAbsoluteSum(i, j, k);
if (distance > 0 && distance < minDistance && world.getBlock(x + i, y + j, z + k) == DimDoors.blockRift) if (distance > 0 && distance < minDistance && world.getBlockState(pos.add(i, j, k)) == DimDoors.blockRift) {
{ link = getLink(pos.add(i, j, k));
link = getLink(x + i, y + j, z + k); if (link != null) {
if (link != null)
{
nearest = link; nearest = link;
minDistance = distance; minDistance = distance;
} }
@ -267,11 +234,9 @@ public abstract class NewDimData implements IPackable<PackedDimData>
return nearest; return nearest;
} }
public ArrayList<DimLink> findRiftsInRange(World world, int range, int x, int y, int z) public ArrayList<DimLink> findRiftsInRange(World world, int range, BlockPos pos) {
{
// Sanity check... // Sanity check...
if (world.provider.dimensionId != id) if (world.provider.getDimensionId() != id) {
{
throw new IllegalArgumentException("Attempted to search for links in a World instance for a different dimension!"); throw new IllegalArgumentException("Attempted to search for links in a World instance for a different dimension!");
} }
@ -283,18 +248,13 @@ public abstract class NewDimData implements IPackable<PackedDimData>
DDProperties properties = DDProperties.instance(); DDProperties properties = DDProperties.instance();
ArrayList<DimLink> links = new ArrayList<DimLink>(); ArrayList<DimLink> links = new ArrayList<DimLink>();
for (i = -range; i <= range; i++) for (i = -range; i <= range; i++) {
{ for (j = -range; j <= range; j++) {
for (j = -range; j <= range; j++) for (k = -range; k <= range; k++) {
{
for (k = -range; k <= range; k++)
{
distance = getAbsoluteSum(i, j, k); distance = getAbsoluteSum(i, j, k);
if (distance > 0 && world.getBlock(x + i, y + j, z + k) == DimDoors.blockRift) if (distance > 0 && world.getBlockState(pos.add(i, j, k)) == DimDoors.blockRift) {
{ link = getLink(pos.add(i, j, k));
link = getLink(x + i, y + j, z + k); if (link != null) {
if (link != null)
{
links.add(link); links.add(link);
} }
} }
@ -310,66 +270,53 @@ public abstract class NewDimData implements IPackable<PackedDimData>
return Math.abs(i) + Math.abs(j) + Math.abs(k); return Math.abs(i) + Math.abs(j) + Math.abs(k);
} }
public DimLink createLink(int x, int y, int z, LinkType linkType, int orientation) public DimLink createLink(BlockPos pos, LinkType linkType, EnumFacing orientation) {
{ return createLink(new Point4D(pos, id), linkType, orientation, null);
return createLink(new Point4D(x, y, z, id), linkType, orientation, null);
} }
public DimLink createLink(Point4D source, LinkType linkType, int orientation, DDLock locked) public DimLink createLink(Point4D source, LinkType linkType, EnumFacing orientation, DDLock locked) {
{
// Return an existing link if there is one to avoid creating multiple links starting at the same point. // Return an existing link if there is one to avoid creating multiple links starting at the same point.
InnerDimLink link = linkMapping.get(source); InnerDimLink link = linkMapping.get(source);
if (link == null) if (link == null) {
{
link = new InnerDimLink(source, linkType, orientation, locked); link = new InnerDimLink(source, linkType, orientation, locked);
linkMapping.put(source, link); linkMapping.put(source, link);
linkList.add(link); linkList.add(link);
// If this code is running on the server side, add this link to chunkMapping. // If this code is running on the server side, add this link to chunkMapping.
if (linkType != LinkType.CLIENT) if (linkType != LinkType.CLIENT) {
{
ChunkCoordIntPair chunk = link.getChunkCoordinates(); ChunkCoordIntPair chunk = link.getChunkCoordinates();
List<InnerDimLink> chunkLinks = chunkMapping.get(chunk); List<InnerDimLink> chunkLinks = chunkMapping.get(chunk);
if (chunkLinks == null) if (chunkLinks == null) {
{
chunkLinks = new ArrayList<InnerDimLink>(EXPECTED_LINKS_PER_CHUNK); chunkLinks = new ArrayList<InnerDimLink>(EXPECTED_LINKS_PER_CHUNK);
chunkMapping.put(chunk, chunkLinks); chunkMapping.put(chunk, chunkLinks);
} }
chunkLinks.add(link); chunkLinks.add(link);
} }
} } else {
else
{
link.overwrite(linkType, orientation); link.overwrite(linkType, orientation);
} }
modified = true; modified = true;
//Link created! //Link created!
if (linkType != LinkType.CLIENT) if (linkType != LinkType.CLIENT) {
{
linkWatcher.onCreated(new ClientLinkData(link)); linkWatcher.onCreated(new ClientLinkData(link));
} }
return link; return link;
} }
public DimLink createChildLink(int x, int y, int z, DimLink parent) public DimLink createChildLink(BlockPos pos, DimLink parent) {
{ return createChildLink(new Point4D(pos, id), (InnerDimLink) parent, null);
return createChildLink(new Point4D(x, y, z, id), (InnerDimLink) parent, null);
} }
public DimLink createChildLink(Point4D source, DimLink parent, DDLock locked) public DimLink createChildLink(Point4D source, DimLink parent, DDLock locked) {
{
// To avoid having multiple links at a single point, if we find an existing link then we overwrite // To avoid having multiple links at a single point, if we find an existing link then we overwrite
// its destination data instead of creating a new instance. // its destination data instead of creating a new instance.
if (parent == null) if (parent == null) {
{
throw new IllegalArgumentException("parent cannot be null."); throw new IllegalArgumentException("parent cannot be null.");
} }
InnerDimLink link = linkMapping.get(source); InnerDimLink link = linkMapping.get(source);
if (link == null) if (link == null) {
{
link = new InnerDimLink(source, parent, parent.orientation, locked); link = new InnerDimLink(source, parent, parent.orientation, locked);
linkMapping.put(source, link); linkMapping.put(source, link);
linkList.add(link); linkList.add(link);
@ -377,12 +324,10 @@ public abstract class NewDimData implements IPackable<PackedDimData>
// If this code is running on the server side, add this link to chunkMapping. // If this code is running on the server side, add this link to chunkMapping.
// Granted, the client side code should never create child links anyway... // Granted, the client side code should never create child links anyway...
if (link.linkType() != LinkType.CLIENT) if (link.linkType() != LinkType.CLIENT) {
{
ChunkCoordIntPair chunk = link.getChunkCoordinates(); ChunkCoordIntPair chunk = link.getChunkCoordinates();
List<InnerDimLink> chunkLinks = chunkMapping.get(chunk); List<InnerDimLink> chunkLinks = chunkMapping.get(chunk);
if (chunkLinks == null) if (chunkLinks == null) {
{
chunkLinks = new ArrayList<InnerDimLink>(EXPECTED_LINKS_PER_CHUNK); chunkLinks = new ArrayList<InnerDimLink>(EXPECTED_LINKS_PER_CHUNK);
chunkMapping.put(chunk, chunkLinks); chunkMapping.put(chunk, chunkLinks);
} }
@ -391,11 +336,8 @@ public abstract class NewDimData implements IPackable<PackedDimData>
// Link created! // Link created!
linkWatcher.onCreated(new ClientLinkData(link)); linkWatcher.onCreated(new ClientLinkData(link));
} } else {
else if (link.overwrite((InnerDimLink) parent, parent.orientation)) {
{
if (link.overwrite((InnerDimLink) parent, parent.orientation))
{
//Link created! //Link created!
linkWatcher.onCreated(new ClientLinkData(link)); linkWatcher.onCreated(new ClientLinkData(link));
} }
@ -404,24 +346,19 @@ public abstract class NewDimData implements IPackable<PackedDimData>
return link; return link;
} }
public boolean deleteLink(DimLink link) public boolean deleteLink(DimLink link) {
{ if (link.source().getDimension() != id) {
if (link.source().getDimension() != id)
{
throw new IllegalArgumentException("Attempted to delete a link from another dimension."); throw new IllegalArgumentException("Attempted to delete a link from another dimension.");
} }
InnerDimLink target = linkMapping.remove(link.source()); InnerDimLink target = linkMapping.remove(link.source());
if (target != null) if (target != null) {
{
linkList.remove(target); linkList.remove(target);
// If this code is running on the server side, remove this link to chunkMapping. // If this code is running on the server side, remove this link to chunkMapping.
if (link.linkType() != LinkType.CLIENT) if (link.linkType() != LinkType.CLIENT) {
{
ChunkCoordIntPair chunk = target.getChunkCoordinates(); ChunkCoordIntPair chunk = target.getChunkCoordinates();
List<InnerDimLink> chunkLinks = chunkMapping.get(chunk); List<InnerDimLink> chunkLinks = chunkMapping.get(chunk);
if (chunkLinks != null) if (chunkLinks != null) {
{
chunkLinks.remove(target); chunkLinks.remove(target);
} }
} }
@ -435,136 +372,104 @@ public abstract class NewDimData implements IPackable<PackedDimData>
return (target != null); return (target != null);
} }
public boolean deleteLink(int x, int y, int z) public boolean deleteLink(BlockPos pos) {
{ return this.deleteLink(this.getLink(pos));
return this.deleteLink(this.getLink(x, y, z));
} }
public boolean deleteLink(Point4D location)
{ public boolean deleteLink(Point4D location) {
return this.deleteLink(this.getLink(location)); return this.deleteLink(this.getLink(location));
} }
public DimLink getLink(int x, int y, int z) public DimLink getLink(BlockPos location) {
{ return linkMapping.get(new Point4D(location, this.id));
Point4D location = new Point4D(x, y, z, id);
return linkMapping.get(location);
} }
public DimLink getLink(Point3D location) public DimLink getLink(Point4D location) {
{
return linkMapping.get(new Point4D(location.getX(), location.getY(), location.getZ(), this.id));
}
public DimLink getLink(Point4D location)
{
if (location.getDimension() != id) if (location.getDimension() != id)
return null; return null;
return linkMapping.get(location); return linkMapping.get(location);
} }
public ArrayList<DimLink> getAllLinks() public ArrayList<DimLink> getAllLinks() {
{
ArrayList<DimLink> results = new ArrayList<DimLink>(linkMapping.size()); ArrayList<DimLink> results = new ArrayList<DimLink>(linkMapping.size());
results.addAll(linkMapping.values()); results.addAll(linkMapping.values());
return results; return results;
} }
public boolean isPocketDimension() public boolean isPocketDimension() {
{
return (root != this); return (root != this);
} }
public DimensionType type() public DimensionType type() {
{
return this.type; return this.type;
} }
public boolean isFilled()
{ public boolean isFilled() {
return isFilled; return isFilled;
} }
public void setFilled(boolean isFilled) public void setFilled(boolean isFilled) {
{
this.isFilled = isFilled; this.isFilled = isFilled;
this.modified = true; this.modified = true;
} }
public int id() public int id() {
{
return id; return id;
} }
public int depth() public int depth() {
{
return depth; return depth;
} }
public int packDepth() public int packDepth() {
{
return packDepth; return packDepth;
} }
public Point4D origin() public Point4D origin() {
{
return origin; return origin;
} }
public NewDimData parent() public NewDimData parent() {
{
return parent; return parent;
} }
public NewDimData root() public NewDimData root() {
{
return root; return root;
} }
public int orientation() public EnumFacing orientation() {
{
return orientation; return orientation;
} }
public DungeonData dungeon() public DungeonData dungeon() {
{
return dungeon; return dungeon;
} }
public boolean isInitialized() public boolean isInitialized() {
{
return (origin != null); return (origin != null);
} }
public int linkCount() public int linkCount() {
{
return linkList.size(); return linkList.size();
} }
public Iterable<NewDimData> children() public Iterable<NewDimData> children() {
{
return children; return children;
} }
public Iterable<? extends DimLink> links() public Iterable<? extends DimLink> links() {
{
return linkList; return linkList;
} }
public void initializeDungeon(int originX, int originY, int originZ, int orientation, DimLink incoming, DungeonData dungeon) public void initializeDungeon(BlockPos origin, EnumFacing orientation, DimLink incoming, DungeonData dungeon) {
{ if (this.type != DimensionType.DUNGEON) {
if (this.type != DimensionType.DUNGEON)
{
throw new IllegalStateException("Cannot invoke initializeDungeon() on a non-dungeon dimension."); throw new IllegalStateException("Cannot invoke initializeDungeon() on a non-dungeon dimension.");
} } if (isInitialized()) {
if (isInitialized())
{
throw new IllegalStateException("The dimension has already been initialized."); throw new IllegalStateException("The dimension has already been initialized.");
} }
if (orientation < 0 || orientation > 3)
{ setLinkDestination(incoming, origin);
throw new IllegalArgumentException("orientation must be between 0 and 3, inclusive.");
}
setLinkDestination(incoming, originX, originY, originZ);
this.origin = incoming.destination(); this.origin = incoming.destination();
this.orientation = orientation; this.orientation = orientation;
this.dungeon = dungeon; this.dungeon = dungeon;
@ -575,20 +480,19 @@ public abstract class NewDimData implements IPackable<PackedDimData>
/** /**
* Effectively moves the dungeon to the 'top' of a chain as far as dungeon generation is concerned. * Effectively moves the dungeon to the 'top' of a chain as far as dungeon generation is concerned.
*/ */
public void setParentToRoot() public void setParentToRoot() {
{
// Update this dimension's information // Update this dimension's information
if (parent != null) if (parent != null) {
{
parent.children.remove(this); parent.children.remove(this);
} }
this.depth = 1; this.depth = 1;
this.parent = this.root; this.parent = this.root;
this.root.children.add(this); this.root.children.add(this);
this.root.modified = true; this.root.modified = true;
this.modified = true; this.modified = true;
if (this.type == DimensionType.DUNGEON)
{ if (this.type == DimensionType.DUNGEON) {
this.packDepth = calculatePackDepth(this.parent, this.dungeon); this.packDepth = calculatePackDepth(this.parent, this.dungeon);
} }
@ -596,149 +500,120 @@ public abstract class NewDimData implements IPackable<PackedDimData>
Stack<NewDimData> ordering = new Stack<NewDimData>(); Stack<NewDimData> ordering = new Stack<NewDimData>();
ordering.addAll(this.children); ordering.addAll(this.children);
while (!ordering.isEmpty()) while (!ordering.isEmpty()) {
{
NewDimData current = ordering.pop(); NewDimData current = ordering.pop();
current.resetDepth(); current.resetDepth();
ordering.addAll(current.children); ordering.addAll(current.children);
} }
} }
private void resetDepth() private void resetDepth() {
{
// We assume that this is only applied to dimensions with parents // We assume that this is only applied to dimensions with parents
this.depth = this.parent.depth + 1; this.depth = this.parent.depth + 1;
if (this.type == DimensionType.DUNGEON) if (this.type == DimensionType.DUNGEON) {
{
this.packDepth = calculatePackDepth(this.parent, this.dungeon); this.packDepth = calculatePackDepth(this.parent, this.dungeon);
} }
this.modified = true; this.modified = true;
} }
public static int calculatePackDepth(NewDimData parent, DungeonData current) public static int calculatePackDepth(NewDimData parent, DungeonData current) {
{
DungeonData predecessor = parent.dungeon(); DungeonData predecessor = parent.dungeon();
if (current == null) if (current == null) {
{
throw new IllegalArgumentException("current cannot be null."); throw new IllegalArgumentException("current cannot be null.");
} } if (predecessor == null) {
if (predecessor == null)
{
return 1; return 1;
} }
DungeonPack predOwner = predecessor.dungeonType().Owner; DungeonPack predOwner = predecessor.dungeonType().Owner;
DungeonPack currentOwner = current.dungeonType().Owner; DungeonPack currentOwner = current.dungeonType().Owner;
if (currentOwner == null)
{ if (currentOwner == null) {
return 1; return 1;
} } if (predOwner == null) {
if (predOwner == null)
{
return 1; return 1;
} } if (predOwner == currentOwner) {
if (predOwner == currentOwner)
{
return parent.packDepth + 1; return parent.packDepth + 1;
} }
return 1; return 1;
} }
public void initializePocket(int originX, int originY, int originZ, int orientation, DimLink incoming) public void initializePocket(BlockPos origin, EnumFacing orientation, DimLink incoming) {
{ if (!isPocketDimension()) {
if (!isPocketDimension())
{
throw new IllegalStateException("Cannot invoke initializePocket() on a non-pocket dimension."); throw new IllegalStateException("Cannot invoke initializePocket() on a non-pocket dimension.");
} } if (isInitialized()) {
if (isInitialized())
{
throw new IllegalStateException("The dimension has already been initialized."); throw new IllegalStateException("The dimension has already been initialized.");
} }
setLinkDestination(incoming, originX, originY, originZ); setLinkDestination(incoming, origin);
this.origin = incoming.destination(); this.origin = incoming.destination();
this.orientation = orientation; this.orientation = orientation;
this.modified = true; this.modified = true;
} }
public void setLinkDestination(DimLink incoming, int x, int y, int z) public void setLinkDestination(DimLink incoming, BlockPos pos) {
{
InnerDimLink link = (InnerDimLink) incoming; InnerDimLink link = (InnerDimLink) incoming;
link.setDestination(x, y, z, this); link.setDestination(pos, this);
this.modified = true; this.modified = true;
} }
public void lock(DimLink link, boolean locked) public void lock(DimLink link, boolean locked) {
{
InnerDimLink innerLink = (InnerDimLink)link; InnerDimLink innerLink = (InnerDimLink)link;
innerLink.lock.setLockState(locked); innerLink.lock.setLockState(locked);
modified = true; modified = true;
} }
public void setLock(DimLink link, DDLock lock) public void setLock(DimLink link, DDLock lock) {
{
InnerDimLink innerLink = (InnerDimLink)link; InnerDimLink innerLink = (InnerDimLink)link;
innerLink.setLock(lock); innerLink.setLock(lock);
modified = true; modified = true;
} }
public void createLock(DimLink link, ItemStack item, int lockKey) public void createLock(DimLink link, ItemStack item, int lockKey) {
{
InnerDimLink innerLink = (InnerDimLink)link; InnerDimLink innerLink = (InnerDimLink)link;
innerLink.createLock(item, lockKey); innerLink.createLock(item, lockKey);
modified = true; modified = true;
} }
public void removeLock(DimLink link, ItemStack item) public void removeLock(DimLink link, ItemStack item) {
{
InnerDimLink innerLink = (InnerDimLink)link; InnerDimLink innerLink = (InnerDimLink)link;
innerLink.removeLock(item, innerLink); innerLink.removeLock(item, innerLink);
modified = true; modified = true;
} }
public DimLink getRandomLink() public DimLink getRandomLink() {
{ if (linkMapping.isEmpty()) {
if (linkMapping.isEmpty())
{
throw new IllegalStateException("There are no links to select from in this dimension."); throw new IllegalStateException("There are no links to select from in this dimension.");
} } if (linkList.size() > 1) {
if (linkList.size() > 1)
{
return linkList.get(random.nextInt(linkList.size())); return linkList.get(random.nextInt(linkList.size()));
} }
return linkList.get(0); return linkList.get(0);
} }
public Iterable<? extends DimLink> getChunkLinks(int chunkX, int chunkZ) public Iterable<? extends DimLink> getChunkLinks(int chunkX, int chunkZ) {
{
List<InnerDimLink> chunkLinks = chunkMapping.get(new ChunkCoordIntPair(chunkX, chunkZ)); List<InnerDimLink> chunkLinks = chunkMapping.get(new ChunkCoordIntPair(chunkX, chunkZ));
if (chunkLinks != null) if (chunkLinks != null) {
{
return chunkLinks; return chunkLinks;
} }
return new ArrayList<InnerDimLink>(0); return new ArrayList<InnerDimLink>(0);
} }
public boolean isModified() public boolean isModified() {
{
return modified; return modified;
} }
public void clearModified() public void clearModified() {
{
this.modified = false; this.modified = false;
} }
public void clear() public void clear() {
{
// If this dimension has a parent, remove it from its parent's list of children // If this dimension has a parent, remove it from its parent's list of children
if (parent != null) if (parent != null) {
{
parent.children.remove(this); parent.children.remove(this);
} }
// Remove this dimension as the parent of its children // Remove this dimension as the parent of its children
for (NewDimData child : children) for (NewDimData child : children) {
{
child.parent = null; child.parent = null;
} }
// Clear all fields // Clear all fields
@ -754,62 +629,52 @@ public abstract class NewDimData implements IPackable<PackedDimData>
depth = Integer.MIN_VALUE; depth = Integer.MIN_VALUE;
packDepth = Integer.MIN_VALUE; packDepth = Integer.MIN_VALUE;
origin = null; origin = null;
orientation = Integer.MIN_VALUE; orientation = EnumFacing.SOUTH;
dungeon = null; dungeon = null;
linkWatcher = null; linkWatcher = null;
} }
public PackedDimData pack() public PackedDimData pack() {
{
ArrayList<Integer> ChildIDs = new ArrayList<Integer>(); ArrayList<Integer> ChildIDs = new ArrayList<Integer>();
ArrayList<PackedLinkData> Links = new ArrayList<PackedLinkData>(); ArrayList<PackedLinkData> Links = new ArrayList<PackedLinkData>();
ArrayList<PackedLinkTail> Tails = new ArrayList<PackedLinkTail>(); ArrayList<PackedLinkTail> Tails = new ArrayList<PackedLinkTail>();
PackedDungeonData packedDungeon=null; PackedDungeonData packedDungeon=null;
if(this.dungeon!=null) if(this.dungeon!=null) {
{
packedDungeon= new PackedDungeonData(dungeon.weight(), dungeon.isOpen(), dungeon.isInternal(), packedDungeon= new PackedDungeonData(dungeon.weight(), dungeon.isOpen(), dungeon.isInternal(),
dungeon.schematicPath(), dungeon.schematicName(), dungeon.dungeonType().Name, dungeon.schematicPath(), dungeon.schematicName(), dungeon.dungeonType().Name,
dungeon.dungeonType().Owner.getName()); dungeon.dungeonType().Owner.getName());
} }
//Make a list of children //Make a list of children
for(NewDimData data : this.children) for(NewDimData data : this.children) {
{
ChildIDs.add(data.id); ChildIDs.add(data.id);
} }
for(DimLink link:this.links()) for(DimLink link:this.links()) {
{ ArrayList<BlockPos> children = new ArrayList<BlockPos>();
ArrayList<Point3D> children = new ArrayList<Point3D>(); BlockPos parentPoint = new BlockPos(-1,-1,-1);
Point3D parentPoint = new Point3D(-1,-1,-1); if(link.parent!=null) {
if(link.parent!=null) parentPoint=link.parent.point.toBlockPos();
{
parentPoint=link.parent.point.toPoint3D();
} }
for(DimLink childLink : link.children) for(DimLink childLink : link.children) {
{ children.add(childLink.source().toBlockPos());
children.add(childLink.source().toPoint3D());
} }
PackedLinkTail tail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType()); PackedLinkTail tail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType());
Links.add(new PackedLinkData(link.point,parentPoint,tail,link.orientation,children,link.lock)); Links.add(new PackedLinkData(link.point,parentPoint,tail,link.orientation,children,link.lock));
PackedLinkTail tempTail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType()); PackedLinkTail tempTail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType());
if(Tails.contains(tempTail)) if(Tails.contains(tempTail)) {
{
Tails.add(tempTail); Tails.add(tempTail);
} }
} }
int parentID=this.id; int parentID=this.id;
Point3D originPoint=new Point3D(0,0,0); BlockPos originPoint=new BlockPos(0,0,0);
if(this.parent!=null) if(this.parent!=null) {
{
parentID = this.parent.id; parentID = this.parent.id;
} } if(this.origin!=null) {
if(this.origin!=null) originPoint=this.origin.toBlockPos();
{
originPoint=this.origin.toPoint3D();
} }
return new PackedDimData(this.id, depth, this.packDepth, parentID, this.root().id(), orientation, return new PackedDimData(this.id, depth, this.packDepth, parentID, this.root().id(), orientation,
type, isFilled,packedDungeon, originPoint, ChildIDs, Links, Tails); type, isFilled,packedDungeon, originPoint, ChildIDs, Links, Tails);

View file

@ -8,7 +8,6 @@ import java.util.ArrayList;
import java.util.Random; import java.util.Random;
import com.zixiken.dimdoors.DimDoors; import com.zixiken.dimdoors.DimDoors;
import com.zixiken.dimdoors.Point3D;
import com.zixiken.dimdoors.blocks.IDimDoor; import com.zixiken.dimdoors.blocks.IDimDoor;
import com.zixiken.dimdoors.config.DDProperties; import com.zixiken.dimdoors.config.DDProperties;
import com.zixiken.dimdoors.core.DimLink; import com.zixiken.dimdoors.core.DimLink;
@ -22,6 +21,8 @@ import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntitySign; import net.minecraft.tileentity.TileEntitySign;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.World; import net.minecraft.world.World;
import com.zixiken.dimdoors.core.NewDimData; import com.zixiken.dimdoors.core.NewDimData;
import com.zixiken.dimdoors.schematic.BlockRotator; import com.zixiken.dimdoors.schematic.BlockRotator;
@ -37,15 +38,14 @@ public class DungeonSchematic extends Schematic {
private static final int NETHER_DIMENSION_ID = -1; private static final int NETHER_DIMENSION_ID = -1;
private int orientation; private EnumFacing orientation;
private Point3D entranceDoorLocation; private BlockPos entranceDoorLocation;
private ArrayList<Point3D> exitDoorLocations; private ArrayList<BlockPos> exitDoorLocations;
private ArrayList<Point3D> dimensionalDoorLocations; private ArrayList<BlockPos> dimensionalDoorLocations;
private ArrayList<Point3D> monolithSpawnLocations; private ArrayList<BlockPos> monolithSpawnLocations;
private ArrayList<Block> modBlockFilterExceptions; private ArrayList<Block> modBlockFilterExceptions;
private DungeonSchematic(Schematic source) private DungeonSchematic(Schematic source) {
{
super(source); super(source);
modBlockFilterExceptions = new ArrayList<Block>(5); modBlockFilterExceptions = new ArrayList<Block>(5);
modBlockFilterExceptions.add(DimDoors.blockDimWall); modBlockFilterExceptions.add(DimDoors.blockDimWall);
@ -55,54 +55,45 @@ public class DungeonSchematic extends Schematic {
modBlockFilterExceptions.add(DimDoors.transientDoor); modBlockFilterExceptions.add(DimDoors.transientDoor);
} }
public int getOrientation() public EnumFacing getOrientation() {
{
return orientation; return orientation;
} }
public Point3D getEntranceDoorLocation() public BlockPos getEntranceDoorLocation() {
{ return (entranceDoorLocation != null) ? entranceDoorLocation : null;
return (entranceDoorLocation != null) ? entranceDoorLocation.clone() : null;
} }
private DungeonSchematic() private DungeonSchematic() {
{
//Used to create a dummy instance for readFromResource() //Used to create a dummy instance for readFromResource()
super((short) 0, (short) 0, (short) 0, null, null, null); super(BlockPos.ORIGIN, null, null);
} }
public static DungeonSchematic readFromFile(String schematicPath) throws FileNotFoundException, InvalidSchematicException public static DungeonSchematic readFromFile(String schematicPath) throws FileNotFoundException, InvalidSchematicException {
{
return readFromFile(new File(schematicPath)); return readFromFile(new File(schematicPath));
} }
public static DungeonSchematic readFromFile(File schematicFile) throws FileNotFoundException, InvalidSchematicException public static DungeonSchematic readFromFile(File schematicFile) throws FileNotFoundException, InvalidSchematicException {
{
return readFromStream(new FileInputStream(schematicFile)); return readFromStream(new FileInputStream(schematicFile));
} }
public static DungeonSchematic readFromResource(String resourcePath) throws InvalidSchematicException public static DungeonSchematic readFromResource(String resourcePath) throws InvalidSchematicException {
{
//We need an instance of a class in the mod to retrieve a resource //We need an instance of a class in the mod to retrieve a resource
DungeonSchematic empty = new DungeonSchematic(); DungeonSchematic empty = new DungeonSchematic();
InputStream schematicStream = empty.getClass().getResourceAsStream(resourcePath); InputStream schematicStream = empty.getClass().getResourceAsStream(resourcePath);
return readFromStream(schematicStream); return readFromStream(schematicStream);
} }
public static DungeonSchematic readFromStream(InputStream schematicStream) throws InvalidSchematicException public static DungeonSchematic readFromStream(InputStream schematicStream) throws InvalidSchematicException {
{
return new DungeonSchematic(Schematic.readFromStream(schematicStream)); 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) //Search for special blocks (warp doors, dim doors, and end portal frames that mark Monolith spawn points)
SpecialBlockFinder finder = new SpecialBlockFinder(DimDoors.warpDoor, DimDoors.dimensionalDoor, SpecialBlockFinder finder = new SpecialBlockFinder(DimDoors.warpDoor, DimDoors.dimensionalDoor,
Blocks.end_portal_frame, Blocks.sandstone); Blocks.end_portal_frame, Blocks.sandstone);applyFilter(finder);
applyFilter(finder);
//Flip the entrance's orientation to get the dungeon's orientation //Flip the entrance's orientation to get the dungeon's orientation
orientation = BlockRotator.transformMetadata(finder.getEntranceOrientation(), 2, Blocks.wooden_door); orientation = BlockRotator.transformMetadata(finder.getEntranceOrientation(), 2, Blocks.oak_door);
entranceDoorLocation = finder.getEntranceDoorLocation(); entranceDoorLocation = finder.getEntranceDoorLocation();
exitDoorLocations = finder.getExitDoorLocations(); exitDoorLocations = finder.getExitDoorLocations();
@ -111,8 +102,7 @@ public class DungeonSchematic extends Schematic {
//Filter out mod blocks except some of our own //Filter out mod blocks except some of our own
CompoundFilter standardizer = new CompoundFilter(); CompoundFilter standardizer = new CompoundFilter();
standardizer.addFilter(new ModBlockFilter(modBlockFilterExceptions, standardizer.addFilter(new ModBlockFilter(modBlockFilterExceptions, DimDoors.blockDimWall.getDefaultState()));
DimDoors.blockDimWall, (byte) 0));
//Also convert standard DD block IDs to local versions //Also convert standard DD block IDs to local versions
applyFilter(standardizer); applyFilter(standardizer);
@ -126,8 +116,7 @@ public class DungeonSchematic extends Schematic {
//Filter out mod blocks except some of our own //Filter out mod blocks except some of our own
//This comes after ID standardization because the mod block filter relies on standardized IDs //This comes after ID standardization because the mod block filter relies on standardized IDs
standardizer.addFilter(new ModBlockFilter(modBlockFilterExceptions, standardizer.addFilter(new ModBlockFilter(modBlockFilterExceptions, DimDoors.blockDimWall.getDefaultState()));
DimDoors.blockDimWall, (byte) 0));
applyFilter(standardizer); applyFilter(standardizer);
} }
@ -137,7 +126,7 @@ public class DungeonSchematic extends Schematic {
return new DungeonSchematic(Schematic.copyFromWorld(world, x, y, z, width, height, length, doCompactBounds)); return new DungeonSchematic(Schematic.copyFromWorld(world, x, y, z, width, height, length, doCompactBounds));
} }
public void copyToWorld(World world, Point3D pocketCenter, int targetOrientation, DimLink entryLink, public void copyToWorld(World world, BlockPos pocketCenter, int targetOrientation, DimLink entryLink,
Random random, DDProperties properties, boolean notifyClients) Random random, DDProperties properties, boolean notifyClients)
{ {
if (notifyClients) if (notifyClients)
@ -150,8 +139,7 @@ public class DungeonSchematic extends Schematic {
} }
} }
public void copyToWorld(World world, Point3D pocketCenter, int targetOrientation, DimLink entryLink, public void copyToWorld(World world, BlockPos pocketCenter, int targetOrientation, DimLink entryLink, Random random, DDProperties properties, IBlockSetter blockSetter)
Random random, DDProperties properties, IBlockSetter blockSetter)
{ {
//TODO: This function is an improvised solution so we can get the release moving. In the future, //TODO: This function is an improvised solution so we can get the release moving. In the future,
//we should generalize block transformations and implement support for them at the level of Schematic, //we should generalize block transformations and implement support for them at the level of Schematic,
@ -165,7 +153,7 @@ public class DungeonSchematic extends Schematic {
Block block; Block block;
int blockMeta; int blockMeta;
int dx, dy, dz; int dx, dy, dz;
Point3D pocketPoint = new Point3D(0, 0, 0); BlockPos pocketPoint = new BlockPos(0, 0, 0);
//Copy blocks and metadata into the world //Copy blocks and metadata into the world
index = 0; index = 0;
@ -208,11 +196,11 @@ public class DungeonSchematic extends Schematic {
setUpDungeon(PocketManager.createDimensionData(world), world, pocketCenter, turnAngle, entryLink, random, properties, blockSetter); setUpDungeon(PocketManager.createDimensionData(world), world, pocketCenter, turnAngle, entryLink, random, properties, blockSetter);
} }
private void setUpDungeon(NewDimData dimension, World world, Point3D pocketCenter, int turnAngle, DimLink entryLink, Random random, DDProperties properties, IBlockSetter blockSetter) private void setUpDungeon(NewDimData dimension, World world, BlockPos pocketCenter, int turnAngle, DimLink entryLink, Random random, DDProperties properties, IBlockSetter blockSetter)
{ {
//Transform dungeon corners //Transform dungeon corners
Point3D minCorner = new Point3D(0, 0, 0); BlockPos minCorner = new BlockPos(0, 0, 0);
Point3D maxCorner = new Point3D(width - 1, height - 1, length - 1); BlockPos maxCorner = new BlockPos(width - 1, height - 1, length - 1);
transformCorners(entranceDoorLocation, pocketCenter, turnAngle, minCorner, maxCorner); transformCorners(entranceDoorLocation, pocketCenter, turnAngle, minCorner, maxCorner);
//Fill empty chests and dispensers //Fill empty chests and dispensers
@ -223,20 +211,20 @@ public class DungeonSchematic extends Schematic {
createEntranceReverseLink(world, dimension, pocketCenter, entryLink); createEntranceReverseLink(world, dimension, pocketCenter, entryLink);
//Set up link data for dimensional doors //Set up link data for dimensional doors
for (Point3D location : dimensionalDoorLocations) for (BlockPos location : dimensionalDoorLocations)
{ {
createDimensionalDoorLink(world, dimension, location, entranceDoorLocation, turnAngle, pocketCenter); createDimensionalDoorLink(world, dimension, location, entranceDoorLocation, turnAngle, pocketCenter);
} }
//Set up link data for exit door //Set up link data for exit door
for (Point3D location : exitDoorLocations) for (BlockPos location : exitDoorLocations)
{ {
createExitDoorLink(world, dimension, location, entranceDoorLocation, turnAngle, pocketCenter, blockSetter); createExitDoorLink(world, dimension, location, entranceDoorLocation, turnAngle, pocketCenter, blockSetter);
} }
//Remove end portal frames and spawn Monoliths, if allowed //Remove end portal frames and spawn Monoliths, if allowed
boolean canSpawn = CustomLimboPopulator.isMobSpawningAllowed(); boolean canSpawn = CustomLimboPopulator.isMobSpawningAllowed();
for (Point3D location : monolithSpawnLocations) for (BlockPos location : monolithSpawnLocations)
{ {
spawnMonolith(world, location, entranceDoorLocation, turnAngle, pocketCenter, canSpawn, blockSetter); spawnMonolith(world, location, entranceDoorLocation, turnAngle, pocketCenter, canSpawn, blockSetter);
} }
@ -252,32 +240,26 @@ public class DungeonSchematic extends Schematic {
} }
} }
private static void transformCorners(Point3D schematicEntrance, Point3D pocketCenter, int turnAngle, Point3D minCorner, Point3D maxCorner) private static void transformCorners(BlockPos schematicEntrance, BlockPos pocketCenter, EnumFacing turnAngle, BlockPos minCorner, BlockPos maxCorner) {
{
int temp; int temp;
BlockRotator.transformPoint(minCorner, schematicEntrance, turnAngle, pocketCenter); BlockRotator.transformPoint(minCorner, schematicEntrance, turnAngle, pocketCenter);
BlockRotator.transformPoint(maxCorner, schematicEntrance, turnAngle, pocketCenter); BlockRotator.transformPoint(maxCorner, schematicEntrance, turnAngle, pocketCenter);
if (minCorner.getX() > maxCorner.getX()) if (minCorner.getX() > maxCorner.getX()) {
{
temp = minCorner.getX(); temp = minCorner.getX();
minCorner.setX(maxCorner.getX()); minCorner = new BlockPos(maxCorner.getX(), minCorner.getY(), minCorner.getZ());
maxCorner.setX(temp); maxCorner = new BlockPos(temp, maxCorner.getY(), maxCorner.getZ());
} } if (minCorner.getY() > maxCorner.getY()) {
if (minCorner.getY() > maxCorner.getY())
{
temp = minCorner.getY(); temp = minCorner.getY();
minCorner.setY(maxCorner.getY()); minCorner.setY(maxCorner.getY());
maxCorner.setY(temp); maxCorner.setY(temp);
} } if (minCorner.getZ() > maxCorner.getZ()) {
if (minCorner.getZ() > maxCorner.getZ())
{
temp = minCorner.getZ(); temp = minCorner.getZ();
minCorner.setZ(maxCorner.getZ()); minCorner.setZ(maxCorner.getZ());
maxCorner.setZ(temp); maxCorner.setZ(temp);
} }
} }
private static void createEntranceReverseLink(World world, NewDimData dimension, Point3D pocketCenter, DimLink entryLink) private static void createEntranceReverseLink(World world, NewDimData dimension, BlockPos pocketCenter, DimLink entryLink)
{ {
int orientation = world.getBlockMetadata(pocketCenter.getX(), pocketCenter.getY() - 1, pocketCenter.getZ()); int orientation = world.getBlockMetadata(pocketCenter.getX(), pocketCenter.getY() - 1, pocketCenter.getZ());
DimLink reverseLink = dimension.createLink(pocketCenter.getX(), pocketCenter.getY(), pocketCenter.getZ(), LinkType.REVERSE, orientation); DimLink reverseLink = dimension.createLink(pocketCenter.getX(), pocketCenter.getY(), pocketCenter.getZ(), LinkType.REVERSE, orientation);
@ -287,10 +269,10 @@ public class DungeonSchematic extends Schematic {
initDoorTileEntity(world, pocketCenter); initDoorTileEntity(world, pocketCenter);
} }
private static void createExitDoorLink(World world, NewDimData dimension, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter, IBlockSetter blockSetter) private static void createExitDoorLink(World world, NewDimData dimension, BlockPos point, BlockPos entrance, EnumFacing rotation, BlockPos pocketCenter, IBlockSetter blockSetter)
{ {
//Transform the door's location to the pocket coordinate system //Transform the door's location to the pocket coordinate system
Point3D location = point.clone(); BlockPos location = point;
BlockRotator.transformPoint(location, entrance, rotation, pocketCenter); BlockRotator.transformPoint(location, entrance, rotation, pocketCenter);
int orientation = world.getBlockMetadata(location.getX(), location.getY() - 1, location.getZ()); int orientation = world.getBlockMetadata(location.getX(), location.getY() - 1, location.getZ());
dimension.createLink(location.getX(), location.getY(), location.getZ(), LinkType.DUNGEON_EXIT, orientation); dimension.createLink(location.getX(), location.getY(), location.getZ(), LinkType.DUNGEON_EXIT, orientation);
@ -307,10 +289,10 @@ public class DungeonSchematic extends Schematic {
initDoorTileEntity(world, location); initDoorTileEntity(world, location);
} }
private static void createDimensionalDoorLink(World world, NewDimData dimension, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter) private static void createDimensionalDoorLink(World world, NewDimData dimension, BlockPos point, BlockPos entrance, int rotation, BlockPos pocketCenter)
{ {
//Transform the door's location to the pocket coordinate system //Transform the door's location to the pocket coordinate system
Point3D location = point.clone(); BlockPos location = point.clone();
BlockRotator.transformPoint(location, entrance, rotation, pocketCenter); BlockRotator.transformPoint(location, entrance, rotation, pocketCenter);
int orientation = world.getBlockMetadata(location.getX(), location.getY() - 1, location.getZ()); int orientation = world.getBlockMetadata(location.getX(), location.getY() - 1, location.getZ());
@ -318,10 +300,10 @@ public class DungeonSchematic extends Schematic {
initDoorTileEntity(world, location); initDoorTileEntity(world, location);
} }
private static void spawnMonolith(World world, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter, boolean canSpawn, IBlockSetter blockSetter) private static void spawnMonolith(World world, BlockPos point, BlockPos entrance, int rotation, BlockPos pocketCenter, boolean canSpawn, IBlockSetter blockSetter)
{ {
//Transform the frame block's location to the pocket coordinate system //Transform the frame block's location to the pocket coordinate system
Point3D location = point.clone(); BlockPos location = point.clone();
BlockRotator.transformPoint(location, entrance, rotation, pocketCenter); BlockRotator.transformPoint(location, entrance, rotation, pocketCenter);
//Remove frame block //Remove frame block
blockSetter.setBlock(world, location.getX(), location.getY(), location.getZ(), Blocks.air, 0); blockSetter.setBlock(world, location.getX(), location.getY(), location.getZ(), Blocks.air, 0);
@ -334,7 +316,7 @@ public class DungeonSchematic extends Schematic {
} }
} }
private static void initDoorTileEntity(World world, Point3D point) private static void initDoorTileEntity(World world, BlockPos point)
{ {
Block door = world.getBlock(point.getX(), point.getY(), point.getZ()); Block door = world.getBlock(point.getX(), point.getY(), point.getZ());
Block door2 = world.getBlock(point.getX(), point.getY() - 1, point.getZ()); Block door2 = world.getBlock(point.getX(), point.getY() - 1, point.getZ());
@ -350,7 +332,7 @@ public class DungeonSchematic extends Schematic {
} }
} }
private static void writeDepthSign(World world, Point3D pocketCenter, int depth) private static void writeDepthSign(World world, BlockPos pocketCenter, int depth)
{ {
final int SEARCH_RANGE = 6; final int SEARCH_RANGE = 6;

View file

@ -2,42 +2,36 @@ package com.zixiken.dimdoors.dungeon;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import com.zixiken.dimdoors.schematic.SchematicFilter; import com.zixiken.dimdoors.schematic.SchematicFilter;
import net.minecraft.block.state.IBlockState;
import java.util.List; import java.util.List;
public class ModBlockFilter extends SchematicFilter { public class ModBlockFilter extends SchematicFilter {
private List<Block> exceptions; private List<Block> exceptions;
private Block replacementBlock; private IBlockState replacementState;
private byte replacementMetadata;
public ModBlockFilter(List<Block> exceptions, Block replacementBlock, byte replacementMetadata) public ModBlockFilter(List<Block> exceptions, IBlockState state)
{ {
super("ModBlockFilter"); super("ModBlockFilter");
this.exceptions = exceptions; this.exceptions = exceptions;
this.replacementBlock = replacementBlock; this.replacementState = state;
this.replacementMetadata = replacementMetadata;
} }
@Override @Override
protected boolean applyToBlock(int index, Block[] blocks, byte[] metadata) protected boolean applyToBlock(int index, IBlockState[] state) {
{
int k; int k;
Block current = blocks[index]; Block current = state[index].getBlock();
if (!Block.blockRegistry.getNameForObject(current).startsWith("minecraft:")) if (!Block.blockRegistry.getNameForObject(current).getResourcePath().startsWith("minecraft:")) {
{
//This might be a mod block. Check if an exception exists. //This might be a mod block. Check if an exception exists.
for (k = 0; k < exceptions.size(); k++) for (k = 0; k < exceptions.size(); k++) {
{ if (current == exceptions.get(k)) {
if (current == exceptions.get(k))
{
//Exception found, not considered a mod block //Exception found, not considered a mod block
return false; return false;
} }
} }
//No matching exception found. Replace the block. //No matching exception found. Replace the block.
blocks[index] = replacementBlock; state[index] = replacementState;
metadata[index] = replacementMetadata;
return true; return true;
} }
return false; return false;

View file

@ -2,10 +2,13 @@ package com.zixiken.dimdoors.dungeon;
import java.util.ArrayList; import java.util.ArrayList;
import com.zixiken.dimdoors.Point3D;
import com.zixiken.dimdoors.schematic.Schematic; import com.zixiken.dimdoors.schematic.Schematic;
import com.zixiken.dimdoors.schematic.SchematicFilter; import com.zixiken.dimdoors.schematic.SchematicFilter;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
public class SpecialBlockFinder extends SchematicFilter { public class SpecialBlockFinder extends SchematicFilter {
@ -13,94 +16,79 @@ public class SpecialBlockFinder extends SchematicFilter {
private Block dimensionalDoor; private Block dimensionalDoor;
private Block monolithSpawnMarker; private Block monolithSpawnMarker;
private Block exitMarker; private Block exitMarker;
private int entranceOrientation; private EnumFacing entranceOrientation;
private Schematic schematic; private Schematic schematic;
private Point3D entranceDoorLocation; private BlockPos entranceDoorLocation;
private ArrayList<Point3D> exitDoorLocations; private ArrayList<BlockPos> exitDoorLocations;
private ArrayList<Point3D> dimensionalDoorLocations; private ArrayList<BlockPos> dimensionalDoorLocations;
private ArrayList<Point3D> monolithSpawnLocations; private ArrayList<BlockPos> monolithSpawnLocations;
public SpecialBlockFinder(Block warpDoor, Block dimensionalDoor, Block monolithSpawn, Block exitDoor) public SpecialBlockFinder(Block warpDoor, Block dimensionalDoor, Block monolithSpawn, Block exitDoor) {
{
super("SpecialBlockFinder"); super("SpecialBlockFinder");
this.warpDoor = warpDoor; this.warpDoor = warpDoor;
this.dimensionalDoor = dimensionalDoor; this.dimensionalDoor = dimensionalDoor;
this.monolithSpawnMarker = monolithSpawn; this.monolithSpawnMarker = monolithSpawn;
this.exitMarker = exitDoor; this.exitMarker = exitDoor;
this.entranceDoorLocation = null; this.entranceDoorLocation = null;
this.entranceOrientation = 0; this.entranceOrientation = EnumFacing.SOUTH;
this.exitDoorLocations = new ArrayList<Point3D>(); this.exitDoorLocations = new ArrayList<BlockPos>();
this.dimensionalDoorLocations = new ArrayList<Point3D>(); this.dimensionalDoorLocations = new ArrayList<BlockPos>();
this.monolithSpawnLocations = new ArrayList<Point3D>(); this.monolithSpawnLocations = new ArrayList<BlockPos>();
this.schematic = null; this.schematic = null;
} }
public int getEntranceOrientation() { public EnumFacing getEntranceOrientation() {
return entranceOrientation; return entranceOrientation;
} }
public Point3D getEntranceDoorLocation() { public BlockPos getEntranceDoorLocation() {
return entranceDoorLocation; return entranceDoorLocation;
} }
public ArrayList<Point3D> getExitDoorLocations() { public ArrayList<BlockPos> getExitDoorLocations() {
return exitDoorLocations; return exitDoorLocations;
} }
public ArrayList<Point3D> getDimensionalDoorLocations() { public ArrayList<BlockPos> getDimensionalDoorLocations() {
return dimensionalDoorLocations; return dimensionalDoorLocations;
} }
public ArrayList<Point3D> getMonolithSpawnLocations() { public ArrayList<BlockPos> getMonolithSpawnLocations() {
return monolithSpawnLocations; return monolithSpawnLocations;
} }
@Override @Override
protected boolean initialize(Schematic schematic, Block[] blocks, byte[] metadata) protected boolean initialize(Schematic schematic, IBlockState[] state) {
{
this.schematic = schematic; this.schematic = schematic;
return true; return true;
} }
@Override @Override
protected boolean applyToBlock(int index, Block[] blocks, byte[] metadata) protected boolean applyToBlock(int index, IBlockState[] state) {
{
int indexBelow; int indexBelow;
int indexDoubleBelow; int indexDoubleBelow;
if (blocks[index] == monolithSpawnMarker) if (state[index] == monolithSpawnMarker) {
{
monolithSpawnLocations.add(schematic.calculatePoint(index)); monolithSpawnLocations.add(schematic.calculatePoint(index));
return true; return true;
} } if (state[index] == dimensionalDoor) {
if (blocks[index] == dimensionalDoor)
{
indexBelow = schematic.calculateIndexBelow(index); indexBelow = schematic.calculateIndexBelow(index);
if (indexBelow >= 0 && blocks[indexBelow] == dimensionalDoor) if (indexBelow >= 0 && state[indexBelow] == dimensionalDoor) {
{
dimensionalDoorLocations.add(schematic.calculatePoint(index)); dimensionalDoorLocations.add(schematic.calculatePoint(index));
return true; return true;
} } else {
else
{
return false; return false;
} }
} } if (state[index] == warpDoor) {
if (blocks[index] == warpDoor)
{
indexBelow = schematic.calculateIndexBelow(index); indexBelow = schematic.calculateIndexBelow(index);
if (indexBelow >= 0 && blocks[indexBelow] == warpDoor) if (indexBelow >= 0 && state[indexBelow] == warpDoor) {
{
indexDoubleBelow = schematic.calculateIndexBelow(indexBelow); indexDoubleBelow = schematic.calculateIndexBelow(indexBelow);
if (indexDoubleBelow >= 0 && blocks[indexDoubleBelow] == exitMarker) if (indexDoubleBelow >= 0 && state[indexDoubleBelow] == exitMarker) {
{
exitDoorLocations.add(schematic.calculatePoint(index)); exitDoorLocations.add(schematic.calculatePoint(index));
return true; return true;
} } else if (entranceDoorLocation == null) {
else if (entranceDoorLocation == null)
{
entranceDoorLocation = schematic.calculatePoint(index); entranceDoorLocation = schematic.calculatePoint(index);
entranceOrientation = (metadata[indexBelow] & 3); entranceOrientation = state[indexBelow].getValue(BlockDoor.FACING);
return true; return true;
} }
} }
@ -109,8 +97,7 @@ public class SpecialBlockFinder extends SchematicFilter {
} }
@Override @Override
protected boolean terminates() protected boolean terminates() {
{
return false; return false;
} }
} }

View file

@ -1,58 +1,39 @@
package com.zixiken.dimdoors.experimental; package com.zixiken.dimdoors.experimental;
import com.zixiken.dimdoors.Point3D; import com.zixiken.dimdoors.helpers.BlockPosHelper;
import net.minecraft.util.BlockPos;
public class BoundingBox public class BoundingBox {
{ protected BlockPos minCorner;
protected Point3D minCorner; protected BlockPos maxCorner;
protected Point3D maxCorner;
public BoundingBox(int x, int y, int z, int width, int height, int length) public BoundingBox(int x, int y, int z, int width, int height, int length) {
{ this.minCorner = new BlockPos(x, y, z);
this.minCorner = new Point3D(x, y, z); this.maxCorner = new BlockPos(x + width - 1, y + height - 1, z + length - 1);
this.maxCorner = new Point3D(x + width - 1, y + height - 1, z + length - 1);
} }
public BoundingBox(Point3D minCorner, Point3D maxCorner) public BoundingBox(BlockPos minCorner, BlockPos maxCorner) {
{
this.minCorner = minCorner; this.minCorner = minCorner;
this.maxCorner = maxCorner; this.maxCorner = maxCorner;
} }
public int width() public BlockPos volume() {
{ return maxCorner.subtract(minCorner).add(1,1,1);
return (maxCorner.getX() - minCorner.getX() + 1);
} }
public int height() public BlockPos minCorner() {
{
return (maxCorner.getY() - minCorner.getY() + 1);
}
public int length()
{
return (maxCorner.getZ() - minCorner.getZ() + 1);
}
public Point3D minCorner()
{
return minCorner; return minCorner;
} }
public Point3D maxCorner() public BlockPos maxCorner() {
{
return maxCorner; return maxCorner;
} }
public boolean contains(int x, int y, int z) public boolean contains(BlockPos pos) {
{ return BlockPosHelper.between(pos, minCorner, maxCorner);
return ((minCorner.getX() <= x && x <= maxCorner.getX()) &&
(minCorner.getY() <= y && y <= maxCorner.getY()) &&
(minCorner.getZ() <= z && z <= maxCorner.getZ()));
} }
public boolean intersects(BoundingBox other) public boolean intersects(BoundingBox other) {
{
// To be clear, having one box inside another counts as intersecting // To be clear, having one box inside another counts as intersecting
boolean xi = (this.minCorner.getX() <= other.minCorner.getX() && other.minCorner.getX() <= this.maxCorner.getX()) || boolean xi = (this.minCorner.getX() <= other.minCorner.getX() && other.minCorner.getX() <= this.maxCorner.getX()) ||

View file

@ -1,6 +1,7 @@
package com.zixiken.dimdoors.experimental; package com.zixiken.dimdoors.experimental;
import com.zixiken.dimdoors.Point3D; import com.zixiken.dimdoors.Point3D;
import net.minecraft.util.BlockPos;
public class DoorwayData public class DoorwayData
{ {
@ -8,23 +9,23 @@ public class DoorwayData
public static final char Y_AXIS = 'Y'; public static final char Y_AXIS = 'Y';
public static final char Z_AXIS = 'Z'; public static final char Z_AXIS = 'Z';
private Point3D minCorner; private BlockPos minCorner;
private Point3D maxCorner; private BlockPos maxCorner;
private char axis; private char axis;
public DoorwayData(Point3D minCorner, Point3D maxCorner, char axis) public DoorwayData(BlockPos minCorner, BlockPos maxCorner, char axis)
{ {
this.minCorner = minCorner; this.minCorner = minCorner;
this.maxCorner = maxCorner; this.maxCorner = maxCorner;
this.axis = axis; this.axis = axis;
} }
public Point3D minCorner() public BlockPos minCorner()
{ {
return minCorner; return minCorner;
} }
public Point3D maxCorner() public BlockPos maxCorner()
{ {
return maxCorner; return maxCorner;
} }
@ -34,18 +35,7 @@ public class DoorwayData
return axis; return axis;
} }
public int width() public BlockPos volume() {
{ return maxCorner.subtract(minCorner).add(1,1,1);
return (maxCorner.getX() - minCorner.getX() + 1);
}
public int height()
{
return (maxCorner.getY() - minCorner.getY() + 1);
}
public int length()
{
return (maxCorner.getZ() - minCorner.getZ() + 1);
} }
} }

View file

@ -4,19 +4,18 @@ import java.util.Random;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import com.zixiken.dimdoors.Point3D; import com.zixiken.dimdoors.Point3D;
public class MazeBuilder public class MazeBuilder {
{
private MazeBuilder() { } private MazeBuilder() { }
public static void generate(World world, int x, int y, int z, Random random) public static void generate(World world, int x, int y, int z, Random random) {
{
MazeDesign design = MazeDesigner.generate(random); MazeDesign design = MazeDesigner.generate(random);
Point3D offset = new Point3D(x - design.width() / 2, y - design.height() - 1, z - design.length() / 2); BlockPos offset = new BlockPos(x - design.width() / 2, y - design.height() - 1, z - design.length() / 2);
SphereDecayOperation decay = new SphereDecayOperation(random, Blocks.air, 0, Blocks.stonebrick, 2); SphereDecayOperation decay = new SphereDecayOperation(random, Blocks.air, 0, Blocks.stonebrick, 2);
buildRooms(design.getRoomGraph(), world, offset); buildRooms(design.getRoomGraph(), world, offset);
@ -28,12 +27,12 @@ public class MazeBuilder
} }
private static void applyRandomDestruction(MazeDesign design, World world, private static void applyRandomDestruction(MazeDesign design, World world,
Point3D offset, SphereDecayOperation decay, Random random) BlockPos offset, SphereDecayOperation decay, Random random)
{ {
//final int DECAY_BOX_SIZE = 8 //final int DECAY_BOX_SIZE = 8
} }
private static void buildRooms(DirectedGraph<PartitionNode, DoorwayData> roomGraph, World world, Point3D offset) private static void buildRooms(DirectedGraph<PartitionNode, DoorwayData> roomGraph, World world, BlockPos offset)
{ {
for (IGraphNode<PartitionNode, DoorwayData> node : roomGraph.nodes()) for (IGraphNode<PartitionNode, DoorwayData> node : roomGraph.nodes())
{ {
@ -43,10 +42,10 @@ public class MazeBuilder
} }
private static void carveDoorways(DirectedGraph<PartitionNode, DoorwayData> roomGraph, World world, private static void carveDoorways(DirectedGraph<PartitionNode, DoorwayData> roomGraph, World world,
Point3D offset, SphereDecayOperation decay, Random random) BlockPos offset, SphereDecayOperation decay, Random random)
{ {
char axis; char axis;
Point3D lower; BlockPos lower;
DoorwayData doorway; DoorwayData doorway;
for (IGraphNode<PartitionNode, DoorwayData> node : roomGraph.nodes()) for (IGraphNode<PartitionNode, DoorwayData> node : roomGraph.nodes())
@ -168,7 +167,7 @@ public class MazeBuilder
} }
private static void buildBox(World world, Point3D offset, Point3D minCorner, Point3D maxCorner, Block block, int metadata) private static void buildBox(World world, BlockPos offset, BlockPos minCorner, BlockPos maxCorner, Block block, int metadata)
{ {
int minX = minCorner.getX() + offset.getX(); int minX = minCorner.getX() + offset.getX();
int minY = minCorner.getY() + offset.getY(); int minY = minCorner.getY() + offset.getY();

View file

@ -8,8 +8,9 @@ import java.util.Queue;
import java.util.Random; import java.util.Random;
import java.util.Stack; import java.util.Stack;
import com.zixiken.dimdoors.helpers.BlockPosHelper;
import net.minecraft.util.BlockPos;
import net.minecraft.util.MathHelper; import net.minecraft.util.MathHelper;
import com.zixiken.dimdoors.Point3D;
public class MazeDesigner public class MazeDesigner
{ {
@ -22,8 +23,7 @@ public class MazeDesigner
private MazeDesigner() { } private MazeDesigner() { }
public static MazeDesign generate(Random random) public static MazeDesign generate(Random random) {
{
// Construct a random binary space partitioning of our maze volume // Construct a random binary space partitioning of our maze volume
PartitionNode root = partitionRooms(MAZE_WIDTH, MAZE_HEIGHT, MAZE_LENGTH, SPLIT_COUNT, random); PartitionNode root = partitionRooms(MAZE_WIDTH, MAZE_HEIGHT, MAZE_LENGTH, SPLIT_COUNT, random);
@ -48,100 +48,79 @@ public class MazeDesigner
return new MazeDesign(root, rooms, cores); return new MazeDesign(root, rooms, cores);
} }
private static void listRoomPartitions(PartitionNode node, ArrayList<PartitionNode> partitions) private static void listRoomPartitions(PartitionNode node, ArrayList<PartitionNode> partitions) {
{ if (node.isLeaf()) {
if (node.isLeaf())
{
partitions.add(node); partitions.add(node);
} } else {
else
{
listRoomPartitions(node.leftChild(), partitions); listRoomPartitions(node.leftChild(), partitions);
listRoomPartitions(node.rightChild(), partitions); listRoomPartitions(node.rightChild(), partitions);
} }
} }
private static void removeRoomPartitions(PartitionNode node) private static void removeRoomPartitions(PartitionNode node) {
{
// Remove a node and any of its ancestors that become leaf nodes // Remove a node and any of its ancestors that become leaf nodes
PartitionNode parent; PartitionNode parent;
PartitionNode current; PartitionNode current;
current = node; current = node;
while (current != null && current.isLeaf()) while (current != null && current.isLeaf()) {
{
parent = current.parent(); parent = current.parent();
current.remove(); current.remove();
current = parent; current = parent;
} }
} }
private static PartitionNode partitionRooms(int width, int height, int length, int maxLevels, Random random) private static PartitionNode partitionRooms(int width, int height, int length, int maxLevels, Random random) {
{ PartitionNode root = new PartitionNode(new BlockPos(width, height, length));
PartitionNode root = new PartitionNode(width, height, length);
splitByRandomX(root, maxLevels, random); splitByRandomX(root, maxLevels, random);
return root; return root;
} }
private static void splitByRandomX(PartitionNode node, int levels, Random random) private static void splitByRandomX(PartitionNode node, int levels, Random random) {
{ if (node.volume().getX() >= 2 * MIN_SIDE) {
if (node.width() >= 2 * MIN_SIDE)
{
node.splitByX(MathHelper.getRandomIntegerInRange(random, node.splitByX(MathHelper.getRandomIntegerInRange(random,
node.minCorner().getX() + MIN_SIDE, node.maxCorner().getX() - MIN_SIDE + 1)); node.minCorner().getX() + MIN_SIDE, node.maxCorner().getX() - MIN_SIDE + 1));
if (levels > 1) if (levels > 1) {
{
splitByRandomZ(node.leftChild(), levels - 1, random); splitByRandomZ(node.leftChild(), levels - 1, random);
splitByRandomZ(node.rightChild(), levels - 1, random); splitByRandomZ(node.rightChild(), levels - 1, random);
} }
} } else if (levels > 1) {
else if (levels > 1)
{
splitByRandomZ(node, levels - 1, random); splitByRandomZ(node, levels - 1, random);
} }
} }
private static void splitByRandomZ(PartitionNode node, int levels, Random random) private static void splitByRandomZ(PartitionNode node, int levels, Random random)
{ {
if (node.length() >= 2 * MIN_SIDE) if (node.volume().getZ() >= 2 * MIN_SIDE) {
{
node.splitByZ(MathHelper.getRandomIntegerInRange(random, node.splitByZ(MathHelper.getRandomIntegerInRange(random,
node.minCorner().getZ() + MIN_SIDE, node.maxCorner().getZ() - MIN_SIDE + 1)); node.minCorner().getZ() + MIN_SIDE, node.maxCorner().getZ() - MIN_SIDE + 1));
if (levels > 1) if (levels > 1) {
{
splitByRandomY(node.leftChild(), levels - 1, random); splitByRandomY(node.leftChild(), levels - 1, random);
splitByRandomY(node.rightChild(), levels - 1, random); splitByRandomY(node.rightChild(), levels - 1, random);
} }
} }
else if (levels > 1) else if (levels > 1) {
{
splitByRandomY(node, levels - 1, random); splitByRandomY(node, levels - 1, random);
} }
} }
private static void splitByRandomY(PartitionNode node, int levels, Random random) private static void splitByRandomY(PartitionNode node, int levels, Random random) {
{ if (node.volume().getY() >= 2 * MIN_HEIGHT) {
if (node.height() >= 2 * MIN_HEIGHT)
{
node.splitByY(MathHelper.getRandomIntegerInRange(random, node.splitByY(MathHelper.getRandomIntegerInRange(random,
node.minCorner().getY() + MIN_HEIGHT, node.maxCorner().getY() - MIN_HEIGHT + 1)); node.minCorner().getY() + MIN_HEIGHT, node.maxCorner().getY() - MIN_HEIGHT + 1));
if (levels > 1) if (levels > 1) {
{
splitByRandomX(node.leftChild(), levels - 1, random); splitByRandomX(node.leftChild(), levels - 1, random);
splitByRandomX(node.rightChild(), levels - 1, random); splitByRandomX(node.rightChild(), levels - 1, random);
} }
} } else if (levels > 1) {
else if (levels > 1)
{
splitByRandomX(node, levels - 1, random); splitByRandomX(node, levels - 1, random);
} }
} }
private static DirectedGraph<PartitionNode, DoorwayData> createRoomGraph(PartitionNode root, ArrayList<PartitionNode> partitions, Random random) private static DirectedGraph<PartitionNode, DoorwayData> createRoomGraph(PartitionNode root, ArrayList<PartitionNode> partitions, Random random) {
{
DirectedGraph<PartitionNode, DoorwayData> roomGraph = new DirectedGraph<PartitionNode, DoorwayData>(); DirectedGraph<PartitionNode, DoorwayData> roomGraph = new DirectedGraph<PartitionNode, DoorwayData>();
HashMap<PartitionNode, IGraphNode<PartitionNode, DoorwayData>> roomsToGraph = new HashMap<PartitionNode, IGraphNode<PartitionNode, DoorwayData>>(2 * partitions.size()); HashMap<PartitionNode, IGraphNode<PartitionNode, DoorwayData>> roomsToGraph = new HashMap<PartitionNode, IGraphNode<PartitionNode, DoorwayData>>(2 * partitions.size());
@ -152,14 +131,12 @@ public class MazeDesigner
// Add all rooms to a graph // Add all rooms to a graph
// Also add them to a map so we can associate rooms with their graph nodes // Also add them to a map so we can associate rooms with their graph nodes
// The map is needed for linking graph nodes based on adjacent partitions // The map is needed for linking graph nodes based on adjacent partitions
for (PartitionNode partition : partitions) for (PartitionNode partition : partitions) {
{
roomsToGraph.put(partition, roomGraph.addNode(partition)); roomsToGraph.put(partition, roomGraph.addNode(partition));
} }
// Add edges for each room // Add edges for each room
for (IGraphNode<PartitionNode, DoorwayData> node : roomGraph.nodes()) for (IGraphNode<PartitionNode, DoorwayData> node : roomGraph.nodes()) {
{
findDoorways(node, root, roomsToGraph, roomGraph); findDoorways(node, root, roomsToGraph, roomGraph);
} }
@ -168,8 +145,7 @@ public class MazeDesigner
private static void findDoorways(IGraphNode<PartitionNode, DoorwayData> roomNode, PartitionNode root, private static void findDoorways(IGraphNode<PartitionNode, DoorwayData> roomNode, PartitionNode root,
HashMap<PartitionNode, IGraphNode<PartitionNode, DoorwayData>> roomsToGraph, HashMap<PartitionNode, IGraphNode<PartitionNode, DoorwayData>> roomsToGraph,
DirectedGraph<PartitionNode, DoorwayData> roomGraph) DirectedGraph<PartitionNode, DoorwayData> roomGraph) {
{
// This function finds rooms adjacent to a specified room that could be connected // This function finds rooms adjacent to a specified room that could be connected
// to it through a doorway. Edges are added to the room graph to denote rooms that // to it through a doorway. Edges are added to the room graph to denote rooms that
// could be connected. The areas of their common bounds that could be carved // could be connected. The areas of their common bounds that could be carved
@ -190,62 +166,43 @@ public class MazeDesigner
int a, b, c; int a, b, c;
int p, q, r; int p, q, r;
int minXI, minYI, minZI; BlockPos minI;
int maxXI, maxYI, maxZI; BlockPos maxI;
Point3D otherMin; BlockPos diff;
Point3D otherMax; BlockPos otherMin;
BlockPos otherMax;
DoorwayData doorway; DoorwayData doorway;
IGraphNode<PartitionNode, DoorwayData> adjacentNode; IGraphNode<PartitionNode, DoorwayData> adjacentNode;
PartitionNode room = roomNode.data(); PartitionNode room = roomNode.data();
Point3D minCorner = room.minCorner(); BlockPos minCorner = room.minCorner();
Point3D maxCorner = room.maxCorner(); BlockPos maxCorner = room.maxCorner();
int minX = minCorner.getX(); BlockPos volume = room.volume();
int minY = minCorner.getY();
int minZ = minCorner.getZ();
int maxX = maxCorner.getX(); if (maxCorner.getZ() < root.maxCorner().getZ()) {
int maxY = maxCorner.getY();
int maxZ = maxCorner.getZ();
int width = room.width();
int height = room.height();
int length = room.length();
if (maxZ < root.maxCorner().getZ())
{
// Check for adjacent rooms along the XY plane // Check for adjacent rooms along the XY plane
detected = new boolean[width][height]; detected = new boolean[volume.getX()][volume.getY()];
for (a = 0; a < width; a++) for (a = 0; a < volume.getX(); a++) {
{ for (b = 0; b < volume.getY(); b++) {
for (b = 0; b < height; b++) if (!detected[a][b]) {
{ adjacent = root.findPoint(minCorner.add(a, b, 1));
if (!detected[a][b]) if (adjacent != null) {
{
adjacent = root.findPoint(minX + a, minY + b, maxZ + 1);
if (adjacent != null)
{
// Compute the dimensions available for a doorway // Compute the dimensions available for a doorway
otherMin = adjacent.minCorner(); minI = BlockPosHelper.max(minCorner, adjacent.minCorner());
otherMax = adjacent.maxCorner(); maxI = BlockPosHelper.min(maxCorner, adjacent.maxCorner());
minXI = Math.max(minX, otherMin.getX()); diff = maxI.subtract(minI);
maxXI = Math.min(maxX, otherMax.getX());
minYI = Math.max(minY, otherMin.getY());
maxYI = Math.min(maxY, otherMax.getY());
for (p = 0; p <= maxXI - minXI; p++) for (p = 0; p <= diff.getX(); p++) {
{ for (q = 0; q <= diff.getY(); q++) {
for (q = 0; q <= maxYI - minYI; q++)
{
detected[p + a][q + b] = true; detected[p + a][q + b] = true;
} }
} }
// Check if we meet the minimum dimensions needed for a doorway // Check if we meet the minimum dimensions needed for a doorway
if (maxXI - minXI + 1 >= MIN_SIDE && maxYI - minYI + 1 >= MIN_HEIGHT) if (diff.add(1,0,0).getX() + 1 >= MIN_SIDE && maxYI - minYI + 1 >= MIN_HEIGHT)
{ {
otherMin = new Point3D(minXI, minYI, maxZ); otherMin = new BlockPos(minXI, minYI, maxZ);
otherMax = new Point3D(maxXI, maxYI, maxZ + 1); otherMax = new BlockPos(maxXI, maxYI, maxZ + 1);
doorway = new DoorwayData(otherMin, otherMax, DoorwayData.Z_AXIS); doorway = new DoorwayData(otherMin, otherMax, DoorwayData.Z_AXIS);
adjacentNode = roomsToGraph.get(adjacent); adjacentNode = roomsToGraph.get(adjacent);
roomGraph.addEdge(roomNode, adjacentNode, doorway); roomGraph.addEdge(roomNode, adjacentNode, doorway);
@ -292,8 +249,8 @@ public class MazeDesigner
// Check if we meet the minimum dimensions needed for a doorway // Check if we meet the minimum dimensions needed for a doorway
if (maxYI - minYI + 1 >= MIN_HEIGHT && maxZI - minZI + 1 >= MIN_SIDE) if (maxYI - minYI + 1 >= MIN_HEIGHT && maxZI - minZI + 1 >= MIN_SIDE)
{ {
otherMin = new Point3D(maxX, minYI, minZI); otherMin = new BlockPos(maxX, minYI, minZI);
otherMax = new Point3D(maxX + 1, maxYI, maxZI); otherMax = new BlockPos(maxX + 1, maxYI, maxZI);
doorway = new DoorwayData(otherMin, otherMax, DoorwayData.X_AXIS); doorway = new DoorwayData(otherMin, otherMax, DoorwayData.X_AXIS);
adjacentNode = roomsToGraph.get(adjacent); adjacentNode = roomsToGraph.get(adjacent);
roomGraph.addEdge(roomNode, adjacentNode, doorway); roomGraph.addEdge(roomNode, adjacentNode, doorway);
@ -340,8 +297,8 @@ public class MazeDesigner
// Check if we meet the minimum dimensions needed for a doorway // Check if we meet the minimum dimensions needed for a doorway
if (maxXI - minXI + 1 >= MIN_SIDE && maxZI - minZI + 1 >= MIN_SIDE) if (maxXI - minXI + 1 >= MIN_SIDE && maxZI - minZI + 1 >= MIN_SIDE)
{ {
otherMin = new Point3D(minXI, maxY, minZI); otherMin = new BlockPos(minXI, maxY, minZI);
otherMax = new Point3D(maxXI, maxY + 1, maxZI); otherMax = new BlockPos(maxXI, maxY + 1, maxZI);
doorway = new DoorwayData(otherMin, otherMax, DoorwayData.Y_AXIS); doorway = new DoorwayData(otherMin, otherMax, DoorwayData.Y_AXIS);
adjacentNode = roomsToGraph.get(adjacent); adjacentNode = roomsToGraph.get(adjacent);
roomGraph.addEdge(roomNode, adjacentNode, doorway); roomGraph.addEdge(roomNode, adjacentNode, doorway);

View file

@ -1,91 +1,74 @@
package com.zixiken.dimdoors.experimental; package com.zixiken.dimdoors.experimental;
import com.zixiken.dimdoors.Point3D; import com.zixiken.dimdoors.Point3D;
import net.minecraft.util.BlockPos;
import net.minecraft.util.Vec3i;
public class PartitionNode extends BoundingBox public class PartitionNode extends BoundingBox {
{
private PartitionNode parent; private PartitionNode parent;
private PartitionNode leftChild = null; private PartitionNode leftChild = null;
private PartitionNode rightChild = null; private PartitionNode rightChild = null;
public PartitionNode(int width, int height, int length) public PartitionNode(BlockPos volume) {
{ super(new BlockPos(0, 0, 0), volume.subtract(new Vec3i(1,1,1)));
super(new Point3D(0, 0, 0), new Point3D(width - 1, height - 1, length - 1));
parent = null; parent = null;
} }
private PartitionNode(PartitionNode parent, Point3D minCorner, Point3D maxCorner) private PartitionNode(PartitionNode parent, BlockPos minCorner, BlockPos maxCorner)
{ {
super(minCorner, maxCorner); super(minCorner, maxCorner);
this.parent = parent; this.parent = parent;
} }
public boolean isLeaf() public boolean isLeaf() {
{
return (leftChild == null && rightChild == null); return (leftChild == null && rightChild == null);
} }
public PartitionNode leftChild() public PartitionNode leftChild() {
{
return leftChild; return leftChild;
} }
public PartitionNode rightChild() public PartitionNode rightChild() {
{
return rightChild; return rightChild;
} }
public PartitionNode parent() public PartitionNode parent() {
{
return parent; return parent;
} }
public void splitByX(int rightStart) public void splitByX(int rightStart) {
{ if (!this.isLeaf()) {
if (!this.isLeaf())
{
throw new IllegalStateException("This node has already been split."); throw new IllegalStateException("This node has already been split.");
} if (rightStart <= minCorner.getX() || rightStart > maxCorner.getX()) {
throw new IllegalArgumentException("The specified cutting plane is invalid.");
} }
if (rightStart <= minCorner.getX() || rightStart > maxCorner.getX()) leftChild = new PartitionNode(this, minCorner, new BlockPos(rightStart - 1, maxCorner.getY(), maxCorner.getZ()));
rightChild = new PartitionNode(this, new BlockPos(rightStart, minCorner.getY(), minCorner.getZ()), maxCorner);
}
public void splitByY(int rightStart) {
if (!this.isLeaf()) {
throw new IllegalStateException("This node has already been split.");
} if (rightStart <= minCorner.getY() || rightStart > maxCorner.getY()) {
throw new IllegalArgumentException("The specified cutting plane is invalid.");
}
leftChild = new PartitionNode(this, minCorner, new BlockPos(maxCorner.getX(), rightStart - 1, maxCorner.getZ()));
rightChild = new PartitionNode(this, new BlockPos(minCorner.getX(), rightStart, minCorner.getZ()), maxCorner);
}
public void splitByZ(int rightStart) {
if (!this.isLeaf()) {
throw new IllegalStateException("This node has already been split.");
} if (rightStart <= minCorner.getZ() || rightStart > maxCorner.getZ())
{ {
throw new IllegalArgumentException("The specified cutting plane is invalid."); throw new IllegalArgumentException("The specified cutting plane is invalid.");
} }
leftChild = new PartitionNode(this, minCorner, new Point3D(rightStart - 1, maxCorner.getY(), maxCorner.getZ())); leftChild = new PartitionNode(this, minCorner, new BlockPos(maxCorner.getX(), maxCorner.getY(), rightStart - 1));
rightChild = new PartitionNode(this, new Point3D(rightStart, minCorner.getY(), minCorner.getZ()), maxCorner); rightChild = new PartitionNode(this, new BlockPos(minCorner.getX(), minCorner.getY(), rightStart), maxCorner);
} }
public void splitByY(int rightStart) public void remove() {
{ if (parent != null) {
if (!this.isLeaf())
{
throw new IllegalStateException("This node has already been split.");
}
if (rightStart <= minCorner.getY() || rightStart > maxCorner.getY())
{
throw new IllegalArgumentException("The specified cutting plane is invalid.");
}
leftChild = new PartitionNode(this, minCorner, new Point3D(maxCorner.getX(), rightStart - 1, maxCorner.getZ()));
rightChild = new PartitionNode(this, new Point3D(minCorner.getX(), rightStart, minCorner.getZ()), maxCorner);
}
public void splitByZ(int rightStart)
{
if (!this.isLeaf())
{
throw new IllegalStateException("This node has already been split.");
}
if (rightStart <= minCorner.getZ() || rightStart > maxCorner.getZ())
{
throw new IllegalArgumentException("The specified cutting plane is invalid.");
}
leftChild = new PartitionNode(this, minCorner, new Point3D(maxCorner.getX(), maxCorner.getY(), rightStart - 1));
rightChild = new PartitionNode(this, new Point3D(minCorner.getX(), minCorner.getY(), rightStart), maxCorner);
}
public void remove()
{
if (parent != null)
{
if (parent.leftChild == this) if (parent.leftChild == this)
parent.leftChild = null; parent.leftChild = null;
else else
@ -94,31 +77,21 @@ public class PartitionNode extends BoundingBox
} }
} }
public PartitionNode findPoint(int x, int y, int z) public PartitionNode findPoint(BlockPos pos) {
{
// Find the lowest node that contains the specified point or return null // Find the lowest node that contains the specified point or return null
if (this.contains(x, y, z)) if (this.contains(pos)) {
{ return this.findPointInternal(pos);
return this.findPointInternal(x, y, z); } else {
}
else
{
return null; return null;
} }
} }
private PartitionNode findPointInternal(int x, int y, int z) private PartitionNode findPointInternal(BlockPos pos) {
{ if (leftChild != null && leftChild.contains(pos)) {
if (leftChild != null && leftChild.contains(x, y, z)) return leftChild.findPointInternal(pos);
{ } else if (rightChild != null && rightChild.contains(pos)) {
return leftChild.findPointInternal(x, y, z); return rightChild.findPointInternal(pos);
} } else {
else if (rightChild != null && rightChild.contains(x, y, z))
{
return rightChild.findPointInternal(x, y, z);
}
else
{
return this; return this;
} }
} }

View file

@ -0,0 +1,30 @@
package com.zixiken.dimdoors.helpers;
import net.minecraft.util.BlockPos;
/**
* Created by Jared Johnson on 6/22/2016.
*/
public class BlockPosHelper {
public static boolean between(BlockPos pos, BlockPos min, BlockPos max) {
return ((min.getX() <= pos.getX() && pos.getX() <= max.getX()) &&
(min.getY() <= pos.getY() && pos.getY() <= max.getY()) &&
(min.getZ() <= pos.getZ() && pos.getZ() <= max.getZ()));
}
public static BlockPos max(BlockPos a, BlockPos b) {
return new BlockPos(Math.max(a.getX(), b.getX()), Math.max(a.getY(), b.getY()), Math.max(a.getZ(), b.getZ()));
}
public static BlockPos min(BlockPos a, BlockPos b) {
return new BlockPos(Math.min(a.getX(), b.getX()), Math.min(a.getY(), b.getY()), Math.min(a.getZ(), b.getZ()));
}
public static boolean greaterThan(BlockPos a, BlockPos b) {
return (a.getX() > b.getX() && a.getY() > b.getY() && a.getZ() > b.getZ());
}
public static boolean lessThan(BlockPos a, BlockPos b) {
return (a.getX() < b.getX() && a.getY() < b.getY() && a.getZ() < b.getZ());
}
}

View file

@ -65,8 +65,8 @@ public class ChunkLoaderHelper implements LoadingCallback
public static void forcePocketChunks(NewDimData pocket, Ticket ticket) public static void forcePocketChunks(NewDimData pocket, Ticket ticket)
{ {
BoundingBox bounds = PocketBuilder.calculateDefaultBounds(pocket); BoundingBox bounds = PocketBuilder.calculateDefaultBounds(pocket);
Point3D minCorner = bounds.minCorner(); BlockPos minCorner = bounds.minCorner();
Point3D maxCorner = bounds.maxCorner(); BlockPos maxCorner = bounds.maxCorner();
int minX = minCorner.getX() >> 4; int minX = minCorner.getX() >> 4;
int minZ = minCorner.getZ() >> 4; int minZ = minCorner.getZ() >> 4;
int maxX = maxCorner.getX() >> 4; int maxX = maxCorner.getX() >> 4;

View file

@ -17,8 +17,7 @@ public class Compactor
{ {
@SuppressWarnings("unused") // ? @SuppressWarnings("unused") // ?
private static class DimComparator implements Comparator<NewDimData> private static class DimComparator implements Comparator<NewDimData> {
{
@Override @Override
public int compare(NewDimData a, NewDimData b) public int compare(NewDimData a, NewDimData b)
{ {
@ -26,18 +25,15 @@ public class Compactor
} }
} }
public static void write(Collection<? extends NewDimData> values, ByteBuf output) throws IOException public static void write(Collection<? extends NewDimData> values, ByteBuf output) throws IOException {
{
// SenseiKiwi: Just encode the data straight up for now. I'll implement fancier compression later. // SenseiKiwi: Just encode the data straight up for now. I'll implement fancier compression later.
output.writeInt(values.size()); output.writeInt(values.size());
for (NewDimData dimension : values) for (NewDimData dimension : values) {
{
output.writeInt(dimension.id()); output.writeInt(dimension.id());
output.writeInt(dimension.root().id()); output.writeInt(dimension.root().id());
output.writeInt(dimension.type().index); output.writeInt(dimension.type().index);
output.writeInt(dimension.linkCount()); output.writeInt(dimension.linkCount());
for (DimLink link : dimension.links()) for (DimLink link : dimension.links()) {
{
(new ClientLinkData(link)).write(output); (new ClientLinkData(link)).write(output);
} }
} }
@ -55,29 +51,25 @@ public class Compactor
*/ */
} }
public static void readDimensions(ByteBuf input, IDimRegistrationCallback callback) throws IOException public static void readDimensions(ByteBuf input, IDimRegistrationCallback callback) throws IOException {
{
// Read in the dimensions one by one. Make sure we register root dimensions before // Read in the dimensions one by one. Make sure we register root dimensions before
// attempting to register the dimensions under them. // attempting to register the dimensions under them.
HashSet<Integer> rootIDs = new HashSet<Integer>(); HashSet<Integer> rootIDs = new HashSet<Integer>();
int dimCount = input.readInt(); int dimCount = input.readInt();
for (int k = 0; k < dimCount; k++) for (int k = 0; k < dimCount; k++) {
{
int id = input.readInt(); int id = input.readInt();
int rootID = input.readInt(); int rootID = input.readInt();
DimensionType type = DimensionType.getTypeFromIndex(input.readInt()); DimensionType type = DimensionType.getTypeFromIndex(input.readInt());
if (rootIDs.add(rootID)) if (rootIDs.add(rootID)) {
{
callback.registerDimension(rootID, rootID, type); callback.registerDimension(rootID, rootID, type);
} }
// Don't check if (id != rootID) - we want to retrieve the reference anyway // Don't check if (id != rootID) - we want to retrieve the reference anyway
NewDimData dimension = callback.registerDimension(id, rootID, type); NewDimData dimension = callback.registerDimension(id, rootID, type);
int linkCount = input.readInt(); int linkCount = input.readInt();
for (int h = 0; h < linkCount; h++) for (int h = 0; h < linkCount; h++) {
{
ClientLinkData link = ClientLinkData.read(input); ClientLinkData link = ClientLinkData.read(input);
Point4D source = link.point; Point4D source = link.point;
dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkType.CLIENT,0); dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkType.CLIENT,0);

View file

@ -2,31 +2,21 @@ package com.zixiken.dimdoors.helpers;
import java.io.File; import java.io.File;
public class DeleteFolder public class DeleteFolder {
{ public static boolean deleteFolder(File directory) {
public static boolean deleteFolder(File directory) try {
{
try
{
File[] contents = directory.listFiles(); File[] contents = directory.listFiles();
if (contents != null) if (contents != null) {
{ for (File entry : contents) {
for (File entry : contents) if (entry.isDirectory()) {
{
if (entry.isDirectory())
{
deleteFolder(entry); deleteFolder(entry);
} } else {
else
{
entry.delete(); entry.delete();
} }
} }
} }
return directory.delete(); return directory.delete();
} } catch (Exception e) {
catch (Exception e)
{
e.printStackTrace(); e.printStackTrace();
return false; return false;
} }

View file

@ -1,6 +1,5 @@
package com.zixiken.dimdoors.helpers; package com.zixiken.dimdoors.helpers;
public class PersonalPocketHelper public class PersonalPocketHelper {
{
} }

View file

@ -6,12 +6,9 @@ import java.io.OutputStream;
import com.zixiken.dimdoors.DimDoors; import com.zixiken.dimdoors.DimDoors;
public class copyfile public class copyfile {
{ public static boolean copyFile(String ori, String dest) {
public static boolean copyFile(String ori, String dest) try {
{
try
{
//Note: For this to work properly, you must use getClass() on an instance of the class, //Note: For this to work properly, you must use getClass() on an instance of the class,
//not on the value obtained from .class. That was what caused this code to fail before. //not on the value obtained from .class. That was what caused this code to fail before.
//SchematicLoader didn't have this problem because we used instances of it. //SchematicLoader didn't have this problem because we used instances of it.
@ -24,9 +21,7 @@ public class copyfile
} }
in.close(); in.close();
out.close(); out.close();
} } catch (Exception e) {
catch (Exception e)
{
System.out.println("Unable to get resource: " + ori); System.out.println("Unable to get resource: " + ori);
return false; return false;
} }

View file

@ -3,6 +3,8 @@ package com.zixiken.dimdoors.helpers;
import com.zixiken.dimdoors.Point3D; import com.zixiken.dimdoors.Point3D;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.material.Material; import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.BlockPos;
import net.minecraft.util.MathHelper; import net.minecraft.util.MathHelper;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
@ -14,14 +16,12 @@ public class yCoordHelper
private yCoordHelper() { } private yCoordHelper() { }
public static int getFirstUncovered(World world, int x, int yStart, int z) public static int getFirstUncovered(World world, int x, int yStart, int z) {
{
return getFirstUncovered(world, x, yStart, z, false); return getFirstUncovered(world, x, yStart, z, false);
} }
public static int getFirstUncovered(World world, int x, int yStart, int z, boolean fromTop) public static int getFirstUncovered(World world, int x, int yStart, int z, boolean fromTop) {
{ Chunk chunk = world.getChunkProvider().provideChunk(x >> 4, z >> 4);
Chunk chunk = world.getChunkProvider().loadChunk(x >> 4, z >> 4);
int localX = x < 0 ? (x % 16) + 16 : (x % 16); int localX = x < 0 ? (x % 16) + 16 : (x % 16);
int localZ = z < 0 ? (z % 16) + 16 : (z % 16); int localZ = z < 0 ? (z % 16) + 16 : (z % 16);
@ -66,8 +66,7 @@ public class yCoordHelper
return (material.isLiquid() || !material.isReplaceable()); return (material.isLiquid() || !material.isReplaceable());
} }
public static Point3D findSafeCubeUp(World world, int x, int startY, int z) public static BlockPos findSafeCubeUp(World world, int x, int startY, int z) {
{
// Search for a 3x2x3 box with solid opaque blocks (without tile entities) // Search for a 3x2x3 box with solid opaque blocks (without tile entities)
// or replaceable blocks underneath. The box must contain either air and // or replaceable blocks underneath. The box must contain either air and
// non-liquid replaceable blocks only. // non-liquid replaceable blocks only.
@ -84,7 +83,8 @@ public class yCoordHelper
Chunk chunk = initializeChunkArea(world, x >> 4, z >> 4); Chunk chunk = initializeChunkArea(world, x >> 4, z >> 4);
int height = world.getActualHeight(); int height = world.getActualHeight();
int y, dx, dz, blockID, metadata; int y, dx, dz, blockID;
IBlockState state;
boolean isSafe; boolean isSafe;
Block block; Block block;
@ -97,39 +97,30 @@ public class yCoordHelper
// Treat non-liquid replaceable blocks like air // Treat non-liquid replaceable blocks like air
// If we find a layer that contains replaceable blocks or solid opaque blocks without // If we find a layer that contains replaceable blocks or solid opaque blocks without
// tile entities, then it can serve as the base where we'll place the player and door. // tile entities, then it can serve as the base where we'll place the player and door.
for (y = Math.max(startY - 1, 0); y < height; y++) for (y = Math.max(startY - 1, 0); y < height; y++) {
{
isSafe = true; isSafe = true;
for (dx = -1; dx <= 1 && isSafe; dx++) for (dx = -1; dx <= 1 && isSafe; dx++) {
{ for (dz = -1; dz <= 1 && isSafe; dz++) {
for (dz = -1; dz <= 1 && isSafe; dz++)
{
block = chunk.getBlock(localX + dx, y, localZ + dz); block = chunk.getBlock(localX + dx, y, localZ + dz);
metadata = chunk.getBlockMetadata(localX + dx, y, localZ + dz); state = chunk.getBlockState(new BlockPos(localX + dx, y, localZ + dz));
if (!block.isAir(world, x, y, z) && (!block.getMaterial().isReplaceable() || block.getMaterial().isLiquid())) if (!block.isAir(world, new BlockPos(x, y, z)) && (!block.getMaterial().isReplaceable() || block.getMaterial().isLiquid())) {
{ if (!block.getMaterial().isReplaceable() && (!block.isOpaqueCube() || block.hasTileEntity(state))) {
if (!block.getMaterial().isReplaceable() && (!block.isOpaqueCube() || block.hasTileEntity(metadata)))
{
isSafe = false; isSafe = false;
} }
layers = 0; layers = 0;
} }
} }
} } if (isSafe) {
if (isSafe)
{
layers++; layers++;
if (layers == 3) if (layers == 3) {
{ return new BlockPos(localX + cornerX, y - 2, localZ + cornerZ);
return new Point3D(localX + cornerX, y - 2, localZ + cornerZ);
} }
} }
} }
return null; return null;
} }
public static Point3D findSafeCubeDown(World world, int x, int startY, int z) public static BlockPos findSafeCubeDown(World world, int x, int startY, int z) {
{
// Search for a 3x2x3 box with solid opaque blocks (without tile entities) // Search for a 3x2x3 box with solid opaque blocks (without tile entities)
// or replaceable blocks underneath. The box must contain either air and // or replaceable blocks underneath. The box must contain either air and
// non-liquid replaceable blocks only. // non-liquid replaceable blocks only.
@ -146,7 +137,8 @@ public class yCoordHelper
Chunk chunk = initializeChunkArea(world, x >> 4, z >> 4); Chunk chunk = initializeChunkArea(world, x >> 4, z >> 4);
int height = world.getActualHeight(); int height = world.getActualHeight();
int y, dx, dz, blockID, metadata; int y, dx, dz, blockID;
IBlockState state;
boolean isSafe; boolean isSafe;
boolean hasBlocks; boolean hasBlocks;
Block block; Block block;
@ -160,34 +152,25 @@ public class yCoordHelper
{ {
isSafe = true; isSafe = true;
hasBlocks = false; hasBlocks = false;
for (dx = -1; dx <= 1 && isSafe; dx++) for (dx = -1; dx <= 1 && isSafe; dx++) {
{ for (dz = -1; dz <= 1 && isSafe; dz++) {
for (dz = -1; dz <= 1 && isSafe; dz++)
{
block = chunk.getBlock(localX + dx, y, localZ + dz); block = chunk.getBlock(localX + dx, y, localZ + dz);
metadata = chunk.getBlockMetadata(localX + dx, y, localZ + dz); state = chunk.getBlockState(new BlockPos(localX + dx, y, localZ + dz));
if (!block.isAir(world,x,y,z) && (!block.getMaterial().isReplaceable() || block.getMaterial().isLiquid())) if (!block.isAir(world, new BlockPos(x,y,z)) && (!block.getMaterial().isReplaceable() || block.getMaterial().isLiquid())) {
{ if (!block.getMaterial().isReplaceable() && (!block.isOpaqueCube() || block.hasTileEntity(state))) {
if (!block.getMaterial().isReplaceable() && (!block.isOpaqueCube() || block.hasTileEntity(metadata))) if (layers >= 3) {
{ return new BlockPos(localX + cornerX, y + 1, localZ + cornerZ);
if (layers >= 3)
{
return new Point3D(localX + cornerX, y + 1, localZ + cornerZ);
} }
isSafe = false; isSafe = false;
} }
hasBlocks = true; hasBlocks = true;
} }
} }
} } if (isSafe) {
if (isSafe)
{
layers++; layers++;
if (hasBlocks) if (hasBlocks) {
{ if (layers >= 3) {
if (layers >= 3) return new BlockPos(localX + cornerX, y, localZ + cornerZ);
{
return new Point3D(localX + cornerX, y, localZ + cornerZ);
} }
layers = 0; layers = 0;
} }
@ -196,26 +179,22 @@ public class yCoordHelper
return null; return null;
} }
private static Chunk initializeChunkArea(World world, int chunkX, int chunkZ) private static Chunk initializeChunkArea(World world, int chunkX, int chunkZ) {
{
// We initialize a 3x3 area of chunks instead of just initializing // We initialize a 3x3 area of chunks instead of just initializing
// the target chunk because things generated in adjacent chunks // the target chunk because things generated in adjacent chunks
// (e.g. trees) might intrude into the target chunk. // (e.g. trees) might intrude into the target chunk.
IChunkProvider provider = world.getChunkProvider(); IChunkProvider provider = world.getChunkProvider();
Chunk target = provider.loadChunk(chunkX, chunkZ); Chunk target = provider.provideChunk(chunkX, chunkZ);
for (int dx = -1; dx <= 1; dx++) for (int dx = -1; dx <= 1; dx++) {
{ for (int dz = -1; dz <= 1; dz++) {
for (int dz = -1; dz <= 1; dz++) provider.provideChunk(chunkX, chunkZ);
{
provider.loadChunk(chunkX, chunkZ);
} }
} }
return target; return target;
} }
public static Point3D findDropPoint(World world, int x, int startY, int z) public static BlockPos findDropPoint(World world, int x, int startY, int z) {
{
// Find a simple 2-block-high air gap // Find a simple 2-block-high air gap
// Search across a 3x3 column // Search across a 3x3 column
final int GAP_HEIGHT = 2; final int GAP_HEIGHT = 2;
@ -234,35 +213,25 @@ public class yCoordHelper
int[] gaps = new int[9]; int[] gaps = new int[9];
// Check 3x3 layers of blocks for air spaces // Check 3x3 layers of blocks for air spaces
for (y = Math.min(startY, height - 1); y > 0; y--) for (y = Math.min(startY, height - 1); y > 0; y--) {
{ for (dx = -1, index = 0; dx <= 1; dx++) {
for (dx = -1, index = 0; dx <= 1; dx++) for (dz = -1; dz <= 1; dz++, index++) {
{ if (!chunk.getBlock(localX + dx, y, localZ + dz).isAir(world, new BlockPos(x+dx, y, z+dz))) {
for (dz = -1; dz <= 1; dz++, index++)
{
if (!chunk.getBlock(localX + dx, y, localZ + dz).isAir(world, x+dx,y,z+dz))
{
gaps[index] = 0; gaps[index] = 0;
} } else {
else
{
gaps[index]++; gaps[index]++;
} }
} }
} }
// Check if an acceptable gap exists in the center of the search column // Check if an acceptable gap exists in the center of the search column
if (gaps[index / 2] == GAP_HEIGHT) if (gaps[index / 2] == GAP_HEIGHT) {
{ return new BlockPos(localX + cornerX, y + GAP_HEIGHT - 1, localZ + cornerZ);
return new Point3D(localX + cornerX, y + GAP_HEIGHT - 1, localZ + cornerZ);
} }
// Check the other positions in the column // Check the other positions in the column
for (dx = -1, index = 0; dx <= 1; dx++) for (dx = -1, index = 0; dx <= 1; dx++) {
{ for (dz = -1; dz <= 1; dz++, index++) {
for (dz = -1; dz <= 1; dz++, index++) if (gaps[index] == GAP_HEIGHT) {
{ return new BlockPos(localX + cornerX + dx, y + GAP_HEIGHT - 1, localZ + cornerZ + dz);
if (gaps[index] == GAP_HEIGHT)
{
return new Point3D(localX + cornerX + dx, y + GAP_HEIGHT - 1, localZ + cornerZ + dz);
} }
} }
} }
@ -270,22 +239,19 @@ public class yCoordHelper
return null; return null;
} }
public static int adjustDestinationY(int y, int worldHeight, int entranceY, int dungeonHeight) public static int adjustDestinationY(int y, int worldHeight, int entranceY, int dungeonHeight) {
{
//The goal here is to guarantee that the dungeon fits within the vertical bounds //The goal here is to guarantee that the dungeon fits within the vertical bounds
//of the world while shifting it as little as possible. //of the world while shifting it as little as possible.
int destY = y; int destY = y;
//Is the top of the dungeon going to be at Y < worldHeight? //Is the top of the dungeon going to be at Y < worldHeight?
int pocketTop = (dungeonHeight - 1) + destY - entranceY; int pocketTop = (dungeonHeight - 1) + destY - entranceY;
if (pocketTop >= worldHeight) if (pocketTop >= worldHeight) {
{
destY = (worldHeight - 1) - (dungeonHeight - 1) + entranceY; destY = (worldHeight - 1) - (dungeonHeight - 1) + entranceY;
} }
//Is the bottom of the dungeon at Y >= 0? //Is the bottom of the dungeon at Y >= 0?
if (destY < entranceY) if (destY < entranceY) {
{
destY = entranceY; destY = entranceY;
} }
return destY; return destY;

View file

@ -199,7 +199,7 @@ public class DDSaveHandler
public static boolean unpackLinkData(List<PackedLinkData> linksToUnpack) public static boolean unpackLinkData(List<PackedLinkData> linksToUnpack)
{ {
Point3D fakePoint = new Point3D(-1,-1,-1); BlockPos fakePoint = new BlockPos(-1,-1,-1);
List<PackedLinkData> unpackedLinks = new ArrayList<PackedLinkData>(); List<PackedLinkData> unpackedLinks = new ArrayList<PackedLinkData>();
/** /**
* sort through the list, unpacking links that do not have parents. * sort through the list, unpacking links that do not have parents.

View file

@ -77,9 +77,9 @@ public class OldSaveImporter
Point4D source = new Point4D(link.locXCoord,link.locYCoord,link.locZCoord,link.locDimID); Point4D source = new Point4D(link.locXCoord,link.locYCoord,link.locZCoord,link.locDimID);
Point4D destintion = new Point4D(link.destXCoord,link.destYCoord,link.destZCoord,link.destDimID); Point4D destintion = new Point4D(link.destXCoord,link.destYCoord,link.destZCoord,link.destDimID);
PackedLinkTail tail = new PackedLinkTail(destintion, LinkType.NORMAL); PackedLinkTail tail = new PackedLinkTail(destintion, LinkType.NORMAL);
List<Point3D> children = new ArrayList<Point3D>(); List<BlockPos> children = new ArrayList<BlockPos>();
PackedLinkData newPackedLink = new PackedLinkData(source, new Point3D(-1,-1,-1), tail, link.linkOrientation,children, null); PackedLinkData newPackedLink = new PackedLinkData(source, new BlockPos(-1,-1,-1), tail, link.linkOrientation,children, null);
newPackedLinkData.add(newPackedLink); newPackedLinkData.add(newPackedLink);
allPackedLinks.add(newPackedLink); allPackedLinks.add(newPackedLink);
@ -104,11 +104,11 @@ public class OldSaveImporter
} }
if(data.isPocket) if(data.isPocket)
{ {
dim = new PackedDimData(data.dimID, data.depth, data.depth, data.exitDimLink.locDimID, data.exitDimLink.locDimID, 0, type, data.hasBeenFilled, null, new Point3D(0,64,0), childDims, newPackedLinkData, null); dim = new PackedDimData(data.dimID, data.depth, data.depth, data.exitDimLink.locDimID, data.exitDimLink.locDimID, 0, type, data.hasBeenFilled, null, new BlockPos(0,64,0), childDims, newPackedLinkData, null);
} }
else else
{ {
dim = new PackedDimData(data.dimID, data.depth, data.depth, data.dimID, data.dimID, 0, type, data.hasBeenFilled, null, new Point3D(0,64,0), childDims, newPackedLinkData, null); dim = new PackedDimData(data.dimID, data.depth, data.depth, data.dimID, data.dimID, 0, type, data.hasBeenFilled, null, new BlockPos(0,64,0), childDims, newPackedLinkData, null);
} }
newPackedDimData.put(dim.ID,dim); newPackedDimData.put(dim.ID,dim);
} }

View file

@ -4,6 +4,8 @@ import java.util.List;
import com.zixiken.dimdoors.Point3D; import com.zixiken.dimdoors.Point3D;
import com.zixiken.dimdoors.core.DimensionType; import com.zixiken.dimdoors.core.DimensionType;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
public class PackedDimData public class PackedDimData
{ {
@ -18,18 +20,17 @@ public class PackedDimData
public final int ParentID; public final int ParentID;
public final int RootID; public final int RootID;
public final PackedDungeonData DungeonData; public final PackedDungeonData DungeonData;
public final Point3D Origin; public final BlockPos Origin;
public final int Orientation; public final EnumFacing Orientation;
public final List<Integer> ChildIDs; public final List<Integer> ChildIDs;
public final List<PackedLinkData> Links; public final List<PackedLinkData> Links;
public final List<PackedLinkTail> Tails; public final List<PackedLinkTail> Tails;
// FIXME Missing dungeon data, not sure how to include it // FIXME Missing dungeon data, not sure how to include it
public PackedDimData(int id, int depth, int packDepth, int parentID, int rootID, int orientation, public PackedDimData(int id, int depth, int packDepth, int parentID, int rootID, EnumFacing orientation,
DimensionType type, boolean isFilled,PackedDungeonData dungeonData, Point3D origin, List<Integer> childIDs, List<PackedLinkData> links, DimensionType type, boolean isFilled, PackedDungeonData dungeonData, BlockPos origin, List<Integer> childIDs, List<PackedLinkData> links,
List<PackedLinkTail> tails) List<PackedLinkTail> tails) {
{
ID = id; ID = id;
Depth = depth; Depth = depth;
PackDepth = packDepth; PackDepth = packDepth;
@ -46,8 +47,7 @@ public class PackedDimData
} }
@Override @Override
public String toString() public String toString() {
{
return "ID= "+this.ID; return "ID= "+this.ID;
} }

View file

@ -5,18 +5,19 @@ import java.util.List;
import com.zixiken.dimdoors.Point3D; import com.zixiken.dimdoors.Point3D;
import com.zixiken.dimdoors.core.DDLock; import com.zixiken.dimdoors.core.DDLock;
import com.zixiken.dimdoors.util.Point4D; import com.zixiken.dimdoors.util.Point4D;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
public class PackedLinkData public class PackedLinkData
{ {
public final Point4D source; public final Point4D source;
public final Point3D parent; public final BlockPos parent;
public final PackedLinkTail tail; public final PackedLinkTail tail;
public final int orientation; public final EnumFacing orientation;
public final List<Point3D> children; public final List<BlockPos> children;
public final DDLock lock; public final DDLock lock;
public PackedLinkData(Point4D source, Point3D parent, PackedLinkTail tail, int orientation, List<Point3D> children, DDLock lock) public PackedLinkData(Point4D source, BlockPos parent, PackedLinkTail tail, EnumFacing orientation, List<BlockPos> children, DDLock lock) {
{
this.source=source; this.source=source;
this.parent=parent; this.parent=parent;
this.tail=tail; this.tail=tail;

View file

@ -3,7 +3,10 @@ package com.zixiken.dimdoors.schematic;
import com.zixiken.dimdoors.DimDoors; import com.zixiken.dimdoors.DimDoors;
import net.minecraft.block.*; import net.minecraft.block.*;
import com.zixiken.dimdoors.Point3D; import com.zixiken.dimdoors.Point3D;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -75,7 +78,7 @@ public class BlockRotator
hasOrientations.put(DimDoors.personalDimDoor, true); hasOrientations.put(DimDoors.personalDimDoor, true);
} }
public static int transformMetadata(int metadata, int turns, Block block) public static IBlockState transformMetadata(IBlockState state, int turns, Block block)
{ {
//I changed rotations to reduce the monstrous code we had. It might be //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 //slightly less efficient, but it's easier to maintain for now. ~SenseiKiwi
@ -88,14 +91,14 @@ public class BlockRotator
{ {
while (turns > 0) while (turns > 0)
{ {
metadata = rotateMetadataBy90(metadata, block); state = rotateMetadataBy90(state, block);
turns--; turns--;
} }
} }
return metadata; return state;
} }
private static int rotateMetadataBy90(int metadata, Block block) private static IBlockState rotateMetadataBy90(IBlockState state, Block block)
{ {
//TODO: Replace this horrible function with something prettier. We promise we will for the next version, //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. //after switching to MC 1.6. PADRE, PLEASE FORGIVE OUR SINS.
@ -501,7 +504,7 @@ public class BlockRotator
return metadata; return metadata;
} }
public static void transformPoint(Point3D position, Point3D srcOrigin, int angle, Point3D destOrigin) public static void transformPoint(BlockPos position, BlockPos srcOrigin, EnumFacing angle, BlockPos destOrigin)
{ {
//This function receives a position (e.g. point in schematic space), translates it relative //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), //to a source coordinate system (e.g. the point that will be the center of a schematic),
@ -512,9 +515,7 @@ public class BlockRotator
//Position is only overwritten at the end, so it's okay to provide it as srcOrigin or destOrigin as well. //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(); BlockPos t = position.subtract(srcOrigin);
int ty = position.getY() - srcOrigin.getY();
int tz = position.getZ() - srcOrigin.getZ();
//"int angle" specifies a rotation consistent with Minecraft's orientation system. //"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. //That means each increment of 1 in angle would be a 90-degree clockwise turn.
@ -522,40 +523,32 @@ public class BlockRotator
//calculated by (B - A). //calculated by (B - A).
//Adjust angle into the expected range //Adjust angle into the expected range
if (angle < 0)
{
int correction = -(angle / 4);
angle = angle + 4 * (correction + 1);
}
angle = angle % 4;
int rx; int rx;
int rz; int rz;
switch (angle)
{ switch (angle) {
case 0: //No rotation case SOUTH: //No rotation
rx = tx; rx = t.getX();
rz = tz; rz = t.getZ();
break; break;
case 1: //90 degrees clockwise case WEST: //90 degrees clockwise
rx = -tz; rx = -t.getZ();
rz = tx; rz = t.getX();
break; break;
case 2: //180 degrees case NORTH: //180 degrees
rx = -tx; rx = -t.getX();
rz = -tz; rz = -t.getZ();
break; break;
case 3: //270 degrees clockwise case EAST: //270 degrees clockwise
rx = tz; rx = t.getZ();
rz = -tx; rz = -t.getX();
break; break;
default: //This should never happen default: //This should never happen
throw new IllegalStateException("Invalid angle value. This should never happen!"); throw new IllegalStateException("Invalid angle value. This should never happen!");
} }
position.setX( rx + destOrigin.getX() ); position = new BlockPos(rx + destOrigin.getX(), t.getY() + destOrigin.getY(), rz + destOrigin.getZ() );
position.setY( ty + destOrigin.getY() );
position.setZ( rz + destOrigin.getZ() );
} }
} }

View file

@ -1,16 +1,13 @@
package com.zixiken.dimdoors.schematic; package com.zixiken.dimdoors.schematic;
import com.zixiken.dimdoors.helpers.BlockPosHelper;
import net.minecraft.block.Block;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import com.zixiken.dimdoors.Point3D;
public class CompactBoundsOperation extends WorldOperation public class CompactBoundsOperation extends WorldOperation {
{ private BlockPos minCorner;
private int minX; private BlockPos maxCorner;
private int minY;
private int minZ;
private int maxX;
private int maxY;
private int maxZ;
public CompactBoundsOperation() public CompactBoundsOperation()
{ {
@ -18,57 +15,39 @@ public class CompactBoundsOperation extends WorldOperation
} }
@Override @Override
protected boolean initialize(World world, int x, int y, int z, int width, int height, int length) protected boolean initialize(World world, BlockPos pos, BlockPos volume) {
{ minCorner = new BlockPos(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
minX = Integer.MAX_VALUE; maxCorner = pos;
minY = Integer.MAX_VALUE;
minZ = Integer.MAX_VALUE;
maxX = x;
maxY = y;
maxZ = z;
return true; return true;
} }
@Override @Override
protected boolean applyToBlock(World world, int x, int y, int z) protected boolean applyToBlock(World world, BlockPos pos) {
{
//This could be done more efficiently, but honestly, this is the simplest approach and it //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. //makes it easy for us to verify that the code is correct.
if (!world.isAirBlock(x, y, z)) if (!world.isAirBlock(pos)) {
{ maxCorner = BlockPosHelper.greaterThan(pos, maxCorner) ? pos : maxCorner;
maxX = x > maxX ? x : maxX; minCorner = BlockPosHelper.lessThan(pos, minCorner) ? pos : minCorner;
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; return true;
} }
@Override @Override
protected boolean finish() protected boolean finish() {
{ if (minCorner.getX() == Integer.MAX_VALUE) {
if (minX == Integer.MAX_VALUE)
{
//The whole search space was empty! //The whole search space was empty!
//Compact the space to a single block. //Compact the space to a single block.
minX = maxX; minCorner = maxCorner;
minY = maxY;
minZ = maxZ;
return false; return false;
} }
return true; return true;
} }
public Point3D getMaxCorner() public BlockPos getMaxCorner() {
{ return maxCorner;
return new Point3D(maxX, maxY, maxZ);
} }
public Point3D getMinCorner() public BlockPos getMinCorner() {
{ return minCorner;
return new Point3D(minX, minY, minZ);
} }
} }

View file

@ -1,6 +1,7 @@
package com.zixiken.dimdoors.schematic; package com.zixiken.dimdoors.schematic;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import java.util.ArrayList; import java.util.ArrayList;
@ -8,8 +9,7 @@ public class CompoundFilter extends SchematicFilter {
private ArrayList<SchematicFilter> filters; private ArrayList<SchematicFilter> filters;
public CompoundFilter() public CompoundFilter() {
{
super("CompoundFilter"); super("CompoundFilter");
filters = new ArrayList<SchematicFilter>(); filters = new ArrayList<SchematicFilter>();
} }
@ -20,12 +20,9 @@ public class CompoundFilter extends SchematicFilter {
} }
@Override @Override
protected boolean initialize(Schematic schematic,Block[] blocks, byte[] metadata) protected boolean initialize(Schematic schematic, IBlockState[] metadata) {
{ for (SchematicFilter filter : filters) {
for (SchematicFilter filter : filters) if (!filter.initialize(schematic, metadata)) {
{
if (!filter.initialize(schematic, blocks, metadata))
{
return false; return false;
} }
} }
@ -33,12 +30,9 @@ public class CompoundFilter extends SchematicFilter {
} }
@Override @Override
protected boolean finish() protected boolean finish() {
{ for (SchematicFilter filter : filters) {
for (SchematicFilter filter : filters) if (!filter.finish()) {
{
if (!filter.finish())
{
return false; return false;
} }
} }
@ -46,12 +40,9 @@ public class CompoundFilter extends SchematicFilter {
} }
@Override @Override
protected boolean applyToBlock(int index, Block[] blocks, byte[] metadata) protected boolean applyToBlock(int index, IBlockState[] state) {
{ for (SchematicFilter filter : filters) {
for (SchematicFilter filter : filters) if (filter.applyToBlock(index, state)) {
{
if (filter.applyToBlock(index, blocks, metadata))
{
return filter.terminates(); return filter.terminates();
} }
} }

View file

@ -1,9 +1,11 @@
package com.zixiken.dimdoors.schematic; package com.zixiken.dimdoors.schematic;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
public interface IBlockSetter public interface IBlockSetter
{ {
public void setBlock(World world, int x, int y, int z, Block block, int metadata); public void setBlock(World world, BlockPos pos, IBlockState state);
} }

View file

@ -10,12 +10,14 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockPos;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World; import net.minecraft.world.World;
import com.zixiken.dimdoors.Point3D;
/** /**
* Represents an MC schematic and provides functions for loading, storing, and manipulating schematics. * Represents an MC schematic and provides functions for loading, storing, and manipulating schematics.
@ -23,162 +25,96 @@ import com.zixiken.dimdoors.Point3D;
*/ */
public class Schematic { public class Schematic {
protected short width; protected BlockPos volume;
protected short height; protected IBlockState[] state;
protected short length;
protected Block[] blocks;
protected byte[] metadata;
protected NBTTagList tileEntities; protected NBTTagList tileEntities;
protected Schematic(short width, short height, short length, String[] blockPalette, short[] blockIds, byte[] metadata, NBTTagList tileEntities) protected Schematic(BlockPos volume, IBlockState[] state, NBTTagList tileEntities) {
{ this.volume = volume;
this.width = width; this.state = state;
this.height = height;
this.length = length;
this.metadata = metadata;
this.tileEntities = tileEntities; this.tileEntities = tileEntities;
if (blockPalette != null)
loadBlockList(blockPalette, blockIds);
} }
protected Schematic(short width, short height, short length, Block[] blocks, byte[] metadata, NBTTagList tileEntities) { protected Schematic(Schematic source) {
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 //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. //source's fields will be inaccessible if the derived class is in another package.
this.width = source.width; this.volume = source.volume;
this.height = source.height; this.state = source.state;
this.length = source.length;
this.blocks = source.blocks;
this.metadata = source.metadata;
this.tileEntities = source.tileEntities; this.tileEntities = source.tileEntities;
} }
private void loadBlockList(String[] blockPalette, short[] blockIds) { public int calculateIndex(BlockPos pos) {
this.blocks = new Block[blockIds.length]; if (pos.getX() < 0 || pos.getX() >= volume.getX())
Block[] blockObjPalette = new Block[blockPalette.length];
for (int i = 0; i < blockPalette.length; i++) {
blockObjPalette[i] = (Block)Block.blockRegistry.getObject(blockPalette[i]);
}
for (int i = 0; i < blockIds.length; i++) {
this.blocks[i] = blockObjPalette[blockIds[i]];
}
}
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"); throw new IndexOutOfBoundsException("x must be non-negative and less than width");
if (y < 0 || y >= height) if (pos.getY() < 0 || pos.getY() >= volume.getY())
throw new IndexOutOfBoundsException("y must be non-negative and less than height"); throw new IndexOutOfBoundsException("y must be non-negative and less than height");
if (z < 0 || z >= length) if (pos.getZ() < 0 || pos.getZ() >= volume.getZ())
throw new IndexOutOfBoundsException("z must be non-negative and less than length"); throw new IndexOutOfBoundsException("z must be non-negative and less than length");
return (y * width * length + z * width + x); return (pos.getY() * volume.getX() * volume.getZ() + pos.getZ() * volume.getX() + pos.getX());
} }
public Point3D calculatePoint(int index) public BlockPos calculatePoint(int index) {
{ int y = index / (volume.getX() * volume.getZ());
int y = index / (width * length); index -= y * volume.getX() * volume.getZ();
index -= y * width * length; int z = index / volume.getX();
int z = index / width; index -= z * volume.getX();
index -= z * width;
int x = index; int x = index;
return new Point3D(x, y, z); return new BlockPos(x, y, z);
} }
public int calculateIndexBelow(int index) public int calculateIndexBelow(int index) {
{ return index - (volume.getX() * volume.getZ());
return index - (width * length);
} }
public short getWidth() public BlockPos getVolume() {
{ return volume;
return width;
} }
public short getHeight() public Block getBlock(BlockPos pos) {
{ return state[calculateIndex(pos)].getBlock();
return height;
} }
public short getLength() public IBlockState getBlockState(BlockPos pos) {
{ return state[calculateIndex(pos)];
return length;
} }
public Block getBlock(int x, int y, int z) public NBTTagList getTileEntities() {
{
return (Block)Block.blockRegistry.getObject(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(); return (NBTTagList) tileEntities.copy();
} }
public static Schematic readFromFile(String schematicPath) throws FileNotFoundException, InvalidSchematicException public static Schematic readFromFile(String schematicPath) throws FileNotFoundException, InvalidSchematicException {
{
return readFromFile(new File(schematicPath)); return readFromFile(new File(schematicPath));
} }
public static Schematic readFromFile(File schematicFile) throws FileNotFoundException, InvalidSchematicException public static Schematic readFromFile(File schematicFile) throws FileNotFoundException, InvalidSchematicException {
{
// There is no resource leak... readFromStream() closes the stream TWICE. // There is no resource leak... readFromStream() closes the stream TWICE.
return readFromStream(new FileInputStream(schematicFile)); return readFromStream(new FileInputStream(schematicFile));
} }
public static Schematic readFromResource(String resourcePath) throws InvalidSchematicException public static Schematic readFromResource(String resourcePath) throws InvalidSchematicException {
{
InputStream schematicStream = Schematic.class.getResourceAsStream(resourcePath); InputStream schematicStream = Schematic.class.getResourceAsStream(resourcePath);
return readFromStream(schematicStream); return readFromStream(schematicStream);
} }
public static Schematic readFromStream(InputStream schematicStream) throws InvalidSchematicException public static Schematic readFromStream(InputStream schematicStream) throws InvalidSchematicException {
{
short width; short width;
short height; short height;
short length; short length;
int volume; int volume;
int pairs; int pairs;
byte[] metadata = null; //block metadata IBlockState[] state = null; //block state
byte[] lowBits = null; //first 8 bits of the block IDs
byte[] highBits = null; //additional 4 bits of the block IDs
short[] blockIds = null; //list of combined block IDs
String[] blockPalette = null;
NBTTagList tileEntities = null; //storage for tile entities in NBT form NBTTagList tileEntities = null; //storage for tile entities in NBT form
NBTTagCompound schematicTag; //the NBT data extracted from the schematic file NBTTagCompound schematicTag; //the NBT data extracted from the schematic file
boolean hasExtendedBlockIDs; //indicates whether the schematic contains extended block IDs
try try {
{ try {
try
{
schematicTag = CompressedStreamTools.readCompressed(schematicStream); schematicTag = CompressedStreamTools.readCompressed(schematicStream);
schematicStream.close(); //readCompressed() probably closes the stream anyway, but close again to be sure. schematicStream.close(); //readCompressed() probably closes the stream anyway, but close again to be sure.
} }
catch (Exception ex) catch (Exception ex) {
{
ex.printStackTrace(); ex.printStackTrace();
throw new InvalidSchematicException("The schematic could not be decoded."); throw new InvalidSchematicException("The schematic could not be decoded.");
@ -197,68 +133,20 @@ public class Schematic {
if (length < 0) if (length < 0)
throw new InvalidSchematicException("The schematic cannot have a negative length."); throw new InvalidSchematicException("The schematic cannot have a negative length.");
NBTTagList nbtPalette = schematicTag.getTagList("Palette", 8);
if (nbtPalette.tagCount() < 1) {
throw new InvalidSchematicException("The schematic must have a valid block palette.");
}
blockPalette = new String[nbtPalette.tagCount()];
for (int i = 0; i < nbtPalette.tagCount(); i++) {
blockPalette[i] = nbtPalette.getStringTagAt(i);
}
//load block info //load block info
lowBits = schematicTag.getByteArray("Blocks"); int[] temp = schematicTag.getIntArray("Data");
highBits = schematicTag.getByteArray("AddBlocks"); state = new IBlockState[temp.length];
metadata = schematicTag.getByteArray("Data");
hasExtendedBlockIDs = (highBits.length != 0);
if (volume != lowBits.length) for(int i = 0; i < temp.length; i++)
throw new InvalidSchematicException("The schematic has data for fewer blocks than its dimensions indicate."); state[i] = Block.getStateById(temp[i]);
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.");
blockIds = new short[volume]; if (volume != state.length)
if (hasExtendedBlockIDs) throw new InvalidSchematicException("The schematic has IBlockState for fewer blocks than its dimensions indicate.");
{
//Combine the split block IDs into a single value
pairs = volume - (volume & 1);
int index;
for (index = 0; index < pairs; index += 2)
{
blockIds[index] = (short) (((highBits[index >> 1] & 0x0F) << 8) + (lowBits[index] & 0xFF));
blockIds[index + 1] = (short) (((highBits[index >> 1] & 0xF0) << 4) + (lowBits[index + 1] & 0xFF));
}
if (index < volume)
{
blockIds[index] = lowBits[index >> 1];
}
}
else
{
//Copy the blockIDs
for (int index = 0; index < volume; index++)
{
blockIds[index] = (short) (lowBits[index] & 0xFF);
}
}
for (int i = 0; i < blockIds.length; i++) {
int paletteIndex = blockIds[i];
if (paletteIndex < 0 || paletteIndex >= blockPalette.length) {
throw new InvalidSchematicException("Block entry referenced a non-existant palette entry.");
}
}
//Get the list of tile entities //Get the list of tile entities
tileEntities = schematicTag.getTagList("TileEntities", 10); tileEntities = schematicTag.getTagList("TileEntities", 10);
Schematic result = new Schematic(width, height, length, blockPalette, blockIds, metadata, tileEntities); Schematic result = new Schematic(new BlockPos(width, height, length), state, tileEntities);
return result; return result;
} }
catch (InvalidSchematicException ex) catch (InvalidSchematicException ex)
@ -272,132 +160,71 @@ public class Schematic {
} }
} }
public static Schematic copyFromWorld(World world, int x, int y, int z, short width, short height, short length, boolean doCompactBounds) public static Schematic copyFromWorld(World world, BlockPos pos, BlockPos volume, boolean doCompactBounds) {
{ if (doCompactBounds) {
if (doCompactBounds)
{
//Adjust the vertical bounds to reasonable values if necessary //Adjust the vertical bounds to reasonable values if necessary
int worldHeight = world.getHeight(); int worldHeight = world.getHeight();
int fixedY = (y < 0) ? 0 : y; int fixedY = (pos.getY() < 0) ? 0 : pos.getY();
int fixedHeight = height + y - fixedY; int fixedHeight = volume.getY() + pos.getY() - fixedY;
if (fixedHeight + fixedY >= worldHeight) if (fixedHeight + fixedY >= worldHeight) {
{
fixedHeight = worldHeight - fixedY; fixedHeight = worldHeight - fixedY;
} }
//Compact the area to be copied to remove empty borders //Compact the area to be copied to remove empty borders
CompactBoundsOperation compactor = new CompactBoundsOperation(); CompactBoundsOperation compactor = new CompactBoundsOperation();
compactor.apply(world, x, fixedY, z, width, fixedHeight, length); compactor.apply(world, new BlockPos(pos.getX(), fixedY, pos.getZ()), new BlockPos(volume.getX(), fixedHeight, volume.getZ()));
Point3D minCorner = compactor.getMinCorner(); BlockPos minCorner = compactor.getMinCorner();
Point3D maxCorner = compactor.getMaxCorner(); BlockPos maxCorner = compactor.getMaxCorner();
short compactWidth = (short) (maxCorner.getX() - minCorner.getX() + 1); BlockPos compact = maxCorner.subtract(minCorner).add(1,1,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(), return copyFromWorld(world, minCorner, compact);
compactWidth, compactHeight, compactLength); } else {
} return copyFromWorld(world, pos, volume);
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) private static Schematic copyFromWorld(World world, BlockPos pos, BlockPos volume) {
{
//Short and sweet ^_^ //Short and sweet ^_^
WorldCopyOperation copier = new WorldCopyOperation(); WorldCopyOperation copier = new WorldCopyOperation();
copier.apply(world, x, y, z, width, height, length); copier.apply(world, pos, volume);
return new Schematic(width, height, length, copier.getBlocks(), copier.getMetadata(), copier.getTileEntities()); return new Schematic(volume, copier.getBlockState(), copier.getTileEntities());
} }
private static boolean encodeBlockIDs(short[] blocks, byte[] lowBits, byte[] highBits) public NBTTagCompound writeToNBT() {
{
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;
}
private static void reduceToPalette(Block[] blocks, List<String> blockPalette, short[] blockIds) {
for (int i = 0; i < blocks.length; i++) {
String blockName = Block.blockRegistry.getNameForObject(blocks[i]);
int blockIndex = blockPalette.indexOf(blockName);
if (blockIndex < 0) {
blockIndex = blockPalette.size();
blockPalette.add(blockName);
}
blockIds[i] = (short)blockIndex;
}
}
public NBTTagCompound writeToNBT()
{
return writeToNBT(true); return writeToNBT(true);
} }
protected NBTTagCompound writeToNBT(boolean copyTileEntities) protected NBTTagCompound writeToNBT(boolean copyTileEntities) {
{ return writeToNBT(volume, state, tileEntities, copyTileEntities);
return writeToNBT(width, height, length, blocks, metadata, tileEntities, copyTileEntities);
} }
protected static NBTTagCompound writeToNBT(short width, short height, short length, Block[] blocks, byte[] metadata, protected static NBTTagCompound writeToNBT(BlockPos volume, IBlockState[] state, NBTTagList tileEntities, boolean copyTileEntities) {
NBTTagList tileEntities, boolean copyTileEntities)
{
//This is the main storage function. Schematics are really compressed NBT tags, so if we can generate //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. //the tags, most of the work is done. All the other storage functions will rely on this one.
NBTTagCompound schematicTag = new NBTTagCompound(); NBTTagCompound schematicTag = new NBTTagCompound();
schematicTag.setShort("Width", width); schematicTag.setInteger("Width", volume.getX());
schematicTag.setShort("Length", length); schematicTag.setInteger("Length", volume.getZ());
schematicTag.setShort("Height", height); schematicTag.setInteger("Height", volume.getY());
schematicTag.setTag("Entities", new NBTTagList()); schematicTag.setTag("Entities", new NBTTagList());
schematicTag.setString("Materials", "Alpha"); schematicTag.setString("Materials", "Alpha");
List<String> blockPalette = new LinkedList<String>(); int[] temp = new int[state.length];
short[] blockIds = new short[blocks.length];
reduceToPalette(blocks, blockPalette, blockIds);
byte[] lowBits = new byte[blocks.length]; for(int i = 0; i < temp.length; i++)
byte[] highBits = new byte[(blocks.length >> 1) + (blocks.length & 1)]; temp[i] = Block.getStateId(state[i]);
boolean hasExtendedIDs = encodeBlockIDs(blockIds, lowBits, highBits);
schematicTag.setByteArray("Blocks", lowBits); schematicTag.setIntArray("Data", temp);
schematicTag.setByteArray("Data", metadata);
if (hasExtendedIDs) if (copyTileEntities) {
{
schematicTag.setByteArray("AddBlocks", highBits);
}
if (copyTileEntities)
{
//Used when the result of this function will be passed outside this class. //Used when the result of this function will be passed outside this class.
//Avoids exposing the private field to external modifications. //Avoids exposing the private field to external modifications.
schematicTag.setTag("TileEntities", tileEntities.copy()); schematicTag.setTag("TileEntities", tileEntities.copy());
} } else {
else
{
//Used when the result of this function is for internal use. //Used when the result of this function is for internal use.
//It's more efficient not to copy the tags unless it's needed. //It's more efficient not to copy the tags unless it's needed.
schematicTag.setTag("TileEntities", tileEntities); schematicTag.setTag("TileEntities", tileEntities);
@ -405,13 +232,11 @@ public class Schematic {
return schematicTag; return schematicTag;
} }
public void writeToFile(String schematicPath) throws IOException public void writeToFile(String schematicPath) throws IOException {
{
writeToFile(new File(schematicPath)); writeToFile(new File(schematicPath));
} }
public void writeToFile(File schematicFile) throws IOException public void writeToFile(File schematicFile) throws IOException {
{
FileOutputStream outputStream = new FileOutputStream(schematicFile); FileOutputStream outputStream = new FileOutputStream(schematicFile);
CompressedStreamTools.writeCompressed(writeToNBT(false), outputStream); CompressedStreamTools.writeCompressed(writeToNBT(false), outputStream);
//writeCompressed() probably closes the stream on its own - call close again just in case. //writeCompressed() probably closes the stream on its own - call close again just in case.
@ -419,25 +244,19 @@ public class Schematic {
outputStream.close(); outputStream.close();
} }
public boolean applyFilter(SchematicFilter filter) public boolean applyFilter(SchematicFilter filter) {
{ return filter.apply(this, this.state);
return filter.apply(this, this.blocks, this.metadata);
} }
public void copyToWorld(World world, int x, int y, int z, boolean notifyClients, boolean ignoreAir) public void copyToWorld(World world, BlockPos pos, boolean notifyClients, boolean ignoreAir) {
{ if (notifyClients) {
if (notifyClients) copyToWorld(world, pos, new WorldBlockSetter(false, true, ignoreAir));
{ } else {
copyToWorld(world, x, y, z, new WorldBlockSetter(false, true, ignoreAir)); copyToWorld(world, pos, new ChunkBlockSetter(ignoreAir));
}
else
{
copyToWorld(world, x, y, z, new ChunkBlockSetter(ignoreAir));
} }
} }
protected void copyToWorld(World world, int x, int y, int z, IBlockSetter blockSetter) protected void copyToWorld(World world, BlockPos pos, IBlockSetter blockSetter) {
{
//This isn't implemented as a WorldOperation because it doesn't quite fit the structure of those operations. //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. //It's not worth the trouble in this case.
int index; int index;
@ -446,13 +265,10 @@ public class Schematic {
//Copy blocks and metadata into the world //Copy blocks and metadata into the world
index = 0; index = 0;
for (dy = 0; dy < height; dy++) for (dy = 0; dy < volume.getY(); dy++) {
{ for (dz = 0; dz < volume.getZ(); dz++) {
for (dz = 0; dz < length; dz++) for (dx = 0; dx < volume.getX(); dx++) {
{ blockSetter.setBlock(world, pos.add(dx, dy, dz), state[index]);
for (dx = 0; dx < width; dx++)
{
blockSetter.setBlock(world, x + dx, y + dy, z + dz, blocks[index], metadata[index]);
index++; index++;
} }
} }
@ -464,14 +280,14 @@ public class Schematic {
{ {
NBTTagCompound tileTag = (NBTTagCompound) tileEntities.getCompoundTagAt(index); NBTTagCompound tileTag = (NBTTagCompound) tileEntities.getCompoundTagAt(index);
//Rewrite its location to be in world coordinates //Rewrite its location to be in world coordinates
dx = tileTag.getInteger("x") + x; dx = tileTag.getInteger("x") + pos.getX();
dy = tileTag.getInteger("y") + y; dy = tileTag.getInteger("y") + pos.getY();
dz = tileTag.getInteger("z") + z; dz = tileTag.getInteger("z") + pos.getZ();
tileTag.setInteger("x", dx); tileTag.setInteger("x", dx);
tileTag.setInteger("y", dy); tileTag.setInteger("y", dy);
tileTag.setInteger("z", dz); tileTag.setInteger("z", dz);
//Load the tile entity and put it in the world //Load the tile entity and put it in the world
world.setTileEntity(dx, dy, dz, TileEntity.createAndLoadEntity(tileTag)); world.setTileEntity(new BlockPos(dx, dy, dz), TileEntity.createAndLoadEntity(tileTag));
} }
} }
} }

View file

@ -1,58 +1,51 @@
package com.zixiken.dimdoors.schematic; package com.zixiken.dimdoors.schematic;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
public class SchematicFilter { public class SchematicFilter {
private String name; private String name;
protected SchematicFilter(String name) protected SchematicFilter(String name) {
{
this.name = name; this.name = name;
} }
public String getName() public String getName() {
{
return name; return name;
} }
public boolean apply(Schematic schematic, Block[] blocks, byte[] metadata) public boolean apply(Schematic schematic, IBlockState[] state)
{ {
if (!initialize(schematic, blocks, metadata)) if (!initialize(schematic, state))
return false; return false;
for (int index = 0; index < blocks.length; index++) for (int index = 0; index < state.length; index++) {
{ if (applyToBlock(index, state) && terminates())
if (applyToBlock(index, blocks, metadata) && terminates())
return false; return false;
} }
return finish(); return finish();
} }
protected boolean initialize(Schematic schematic, Block[] blocks, byte[] metadata) protected boolean initialize(Schematic schematic, IBlockState[] state) {
{
return true; return true;
} }
protected boolean applyToBlock(int index, Block[] blocks, byte[] metadata) protected boolean applyToBlock(int index, IBlockState[] state) {
{
return true; return true;
} }
protected boolean finish() protected boolean finish() {
{
return true; return true;
} }
protected boolean terminates() protected boolean terminates() {
{
return true; return true;
} }
@Override @Override
public String toString() public String toString() {
{
return name; return name;
} }
} }

View file

@ -1,77 +1,59 @@
package com.zixiken.dimdoors.schematic; package com.zixiken.dimdoors.schematic;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
public class WorldCopyOperation extends WorldOperation public class WorldCopyOperation extends WorldOperation {
{ private BlockPos origin;
private int originX;
private int originY;
private int originZ;
private int index; private int index;
private Block[] blocks; private IBlockState[] state;
private byte[] metadata;
private NBTTagList tileEntities; private NBTTagList tileEntities;
public WorldCopyOperation() public WorldCopyOperation() {
{
super("WorldCopyOperation"); super("WorldCopyOperation");
blocks = null; state = null;
metadata = null;
tileEntities = null; tileEntities = null;
} }
@Override @Override
protected boolean initialize(World world, int x, int y, int z, int width, int height, int length) protected boolean initialize(World world, BlockPos pos, BlockPos volume) {
{
index = 0; index = 0;
originX = x; origin = pos;
originY = y; state = new IBlockState[volume.getX() * volume.getY() * volume.getZ()];
originZ = z;
blocks = new Block[width * height * length];
metadata = new byte[width * height * length];
tileEntities = new NBTTagList(); tileEntities = new NBTTagList();
return true; return true;
} }
@Override @Override
protected boolean applyToBlock(World world, int x, int y, int z) protected boolean applyToBlock(World world, BlockPos pos) {
{ state[index] = world.getBlockState(pos);
blocks[index] = world.getBlock(x, y, z);
metadata[index] = (byte) world.getBlockMetadata(x, y, z);
TileEntity tileEntity = world.getTileEntity(x, y, z); TileEntity tileEntity = world.getTileEntity(pos);
if (tileEntity != null) if (tileEntity != null) {
{
//Extract tile entity data //Extract tile entity data
NBTTagCompound tileTag = new NBTTagCompound(); NBTTagCompound tileTag = new NBTTagCompound();
tileEntity.writeToNBT(tileTag); tileEntity.writeToNBT(tileTag);
//Translate the tile entity's position from the world's coordinate system //Translate the tile entity's position from the world's coordinate system
//to the schematic's coordinate system. //to the schematic's coordinate system.
tileTag.setInteger("x", x - originX); tileTag.setInteger("x", pos.getX() - origin.getX());
tileTag.setInteger("y", y - originY); tileTag.setInteger("y", pos.getY() - origin.getY());
tileTag.setInteger("z", z - originZ); tileTag.setInteger("z", pos.getZ() - origin.getZ());
tileEntities.appendTag(tileTag); tileEntities.appendTag(tileTag);
} }
index++; //This works assuming the loops in WorldOperation are done in YZX order index++; //This works assuming the loops in WorldOperation are done in YZX order
return true; return true;
} }
public Block[] getBlocks() public IBlockState[] getBlockState() {
{ return state;
return blocks;
} }
public byte[] getMetadata() public NBTTagList getTileEntities() {
{
return metadata;
}
public NBTTagList getTileEntities()
{
return tileEntities; return tileEntities;
} }
} }

View file

@ -1,6 +1,6 @@
package com.zixiken.dimdoors.schematic; package com.zixiken.dimdoors.schematic;
import com.zixiken.dimdoors.Point3D; import net.minecraft.util.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
public abstract class WorldOperation { public abstract class WorldOperation {
@ -12,48 +12,29 @@ public abstract class WorldOperation {
this.name = name; this.name = name;
} }
protected boolean initialize(World world, int x, int y, int z, int width, int height, int length) protected boolean initialize(World world, BlockPos pos, BlockPos volume) {
{
return true; return true;
} }
protected abstract boolean applyToBlock(World world, int x, int y, int z); protected abstract boolean applyToBlock(World world, BlockPos pos);
protected boolean finish() protected boolean finish() {
{
return true; return true;
} }
public boolean apply(World world, Point3D minCorner, Point3D maxCorner) public boolean apply(World world, BlockPos pos, BlockPos volume) {
{ if (!initialize(world, pos, volume))
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; return false;
int cx, cy, cz; int cx, cy, cz;
int limitX = x + width; BlockPos limit = pos.add(volume);
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 //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. //indeces in some schematic operations. The proper order is YZX.
for (cy = y; cy < limitY; cy++) for (cy = pos.getY(); cy < limit.getY(); cy++) {
{ for (cz = pos.getZ(); cz < limit.getZ(); cz++) {
for (cz = z; cz < limitZ; cz++) for (cx = pos.getX(); cx < limit.getX(); cx++) {
{ if (!applyToBlock(world, new BlockPos(cx, cy, cz)))
for (cx = x; cx < limitX; cx++)
{
if (!applyToBlock(world, cx, cy, cz))
return false; return false;
} }
} }
@ -63,14 +44,12 @@ public abstract class WorldOperation {
} }
public String getName() public String getName() {
{
return name; return name;
} }
@Override @Override
public String toString() public String toString() {
{
return name; return name;
} }
} }

View file

@ -5,44 +5,39 @@ import java.io.*;
import com.zixiken.dimdoors.Point3D; import com.zixiken.dimdoors.Point3D;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.BlockPos;
public final class Point4D implements Comparable<Point4D> public final class Point4D implements Comparable<Point4D>
{ {
private final int x; private final BlockPos pos;
private final int y;
private final int z;
private final int dimension; private final int dimension;
/** /**
* *
* @param x * @param pos
* @param y
* @param z
* @param dimension * @param dimension
*/ */
public Point4D(int x, int y, int z, int dimension) public Point4D(BlockPos pos, int dimension)
{ {
this.x = x; this.pos = pos;
this.y = y;
this.z = z;
this.dimension = dimension; this.dimension = dimension;
} }
public int getX() public int getX()
{ {
return x; return pos.getX();
} }
public int getY() public int getY()
{ {
return y; return pos.getY();
} }
public int getZ() public int getZ()
{ {
return z; return pos.getZ();
} }
public int getDimension() public int getDimension()
@ -51,8 +46,7 @@ public final class Point4D implements Comparable<Point4D>
} }
@Override @Override
public int hashCode() public int hashCode() {
{
//Time for some witchcraft. //Time for some witchcraft.
//The code here is inspired by a discussion on Stack Overflow regarding hash codes for 3D. //The code here is inspired by a discussion on Stack Overflow regarding hash codes for 3D.
//Source: http://stackoverflow.com/questions/9858376/hashcode-for-3d-integer-coordinates-with-high-spatial-coherence //Source: http://stackoverflow.com/questions/9858376/hashcode-for-3d-integer-coordinates-with-high-spatial-coherence
@ -67,153 +61,87 @@ public final class Point4D implements Comparable<Point4D>
hash = 0; hash = 0;
index = 0; index = 0;
for (bit = 0; bit < 8; bit++) for (bit = 0; bit < 8; bit++) {
{ hash |= ((pos.getY() >> bit) & 1) << index;
hash |= ((y >> bit) & 1) << index;
index++; index++;
hash |= ((x >> bit) & 1) << index; hash |= ((pos.getX() >> bit) & 1) << index;
index++; index++;
hash |= ((z >> bit) & 1) << index; hash |= ((pos.getZ() >> bit) & 1) << index;
index++; index++;
} }
for (; bit < 12; bit++) for (; bit < 12; bit++) {
{ hash |= ((pos.getX() >> bit) & 1) << index;
hash |= ((x >> bit) & 1) << index;
index++; index++;
hash |= ((z >> bit) & 1) << index; hash |= ((pos.getZ() >> bit) & 1) << index;
index++; index++;
} }
return hash; return hash;
} }
public long toSeed()
{
//Time for some witchcraft.
//The code here is inspired by a discussion on Stack Overflow regarding hash codes for 3D.
//Source: http://stackoverflow.com/questions/9858376/hashcode-for-3d-integer-coordinates-with-high-spatial-coherence
//Use 8 bits from Y and 16 bits from X and Z. Mix in 8 bits from the destination dim ID too - that means
//even if you aligned two doors perfectly between two pockets, it's unlikely they would lead to the same dungeon.
//We map bits in reverse order to produce more varied RNG output for nearly-identical points. The reason is
//that Java's Random outputs the 32 MSBs of its internal state to produce its output. If the differences
//between two seeds are small (i.e. in the LSBs), then they will tend to produce similar random outputs anyway!
//Only bother to assign the 48 least-significant bits since Random only takes those bits from its seed.
//NOTE: The casts to long are necessary to get the right results from the bit shifts!!!
int bit;
int index;
long hash;
final int w = this.dimension;
final int x = this.x;
final int y = this.y;
final int z = this.z;
hash = 0;
index = 48;
for (bit = 0; bit < 8; bit++)
{
hash |= (long) ((w >> bit) & 1) << index;
index--;
hash |= (long) ((x >> bit) & 1) << index;
index--;
hash |= (long) ((y >> bit) & 1) << index;
index--;
hash |= (long) ((z >> bit) & 1) << index;
index--;
}
for (; bit < 16; bit++)
{
hash |= (long) ((x >> bit) & 1) << index;
index--;
hash |= (long) ((z >> bit) & 1) << index;
index--;
}
return hash;
}
@Override @Override
public boolean equals(Object obj) public boolean equals(Object obj)
{ {
return equals((Point4D) obj); return equals((Point4D) obj);
} }
public Point3D toPoint3D() public BlockPos toBlockPos() {
{ return new BlockPos(this.pos);
return new Point3D(this.x, this.y, this.z);
} }
public int[] toIntArray() public boolean equals(Point4D other) {
{
return new int[] {x, y, z, dimension};
}
public boolean equals(Point4D other)
{
if (this == other) if (this == other)
return true; return true;
if (other == null) if (other == null)
return false; return false;
return (pos.equals(other.pos) && dimension == other.dimension);
return (x == other.x && y == other.y && z == other.z && dimension == other.dimension);
} }
@Override @Override
public int compareTo(Point4D other) public int compareTo(Point4D other) {
{ BlockPos diff = pos.subtract(other.pos);
int diff = x - other.x; if (diff.getX() != 0)
if (diff != 0) return diff.getX();
return diff; if (diff.getY() != 0)
diff = y - other.y; return diff.getZ();
if (diff != 0) if (diff.getZ() != 0)
return diff; return diff.getZ();
diff = z - other.z;
if (diff != 0)
return diff;
return dimension - other.dimension; return dimension - other.dimension;
} }
@Override @Override
public String toString() public String toString()
{ {
return "(" + x + ", " + y + ", " + z + ", " + dimension + ")"; return "(" + pos + ", " + dimension + ")";
} }
public static void writeToNBT(Point4D point, NBTTagCompound tag) { public static void writeToNBT(Point4D point, NBTTagCompound tag) {
if (point != null) { if (point != null) {
tag.setInteger("X", point.x); tag.setInteger("X", point.getX());
tag.setInteger("Y", point.y); tag.setInteger("Y", point.getY());
tag.setInteger("Z", point.z); tag.setInteger("Z", point.getZ());
tag.setInteger("Dimension", point.dimension); tag.setInteger("Dimension", point.dimension);
} }
} }
public static void write(Point4D point, ByteBuf stream) throws IOException public static void write(Point4D point, ByteBuf stream) throws IOException {
{
stream.writeBoolean(point != null); stream.writeBoolean(point != null);
if (point != null) if (point != null) {
{ stream.writeInt(point.getX());
stream.writeInt(point.x); stream.writeInt(point.getY());
stream.writeInt(point.y); stream.writeInt(point.getZ());
stream.writeInt(point.z);
stream.writeInt(point.dimension); stream.writeInt(point.dimension);
} }
} }
public static Point4D read(ByteBuf stream) throws IOException public static Point4D read(ByteBuf stream) throws IOException {
{ if (stream.readBoolean()) {
if (stream.readBoolean()) return new Point4D(new BlockPos(stream.readInt(), stream.readInt(), stream.readInt()), stream.readInt() );
{ } else {
return new Point4D( stream.readInt(), stream.readInt(), stream.readInt(), stream.readInt() );
}
else
{
return null; return null;
} }
} }
public static Point4D readFromNBT(NBTTagCompound tag) { public static Point4D readFromNBT(NBTTagCompound tag) {
return new Point4D(tag.getInteger("X"), tag.getInteger("Y"), tag.getInteger("Z"), tag.getInteger("Dimension")); return new Point4D(new BlockPos(tag.getInteger("X"), tag.getInteger("Y"), tag.getInteger("Z")), tag.getInteger("Dimension"));
} }
} }

View file

@ -7,6 +7,8 @@ import com.zixiken.dimdoors.core.DimLink;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.MathHelper; import net.minecraft.util.MathHelper;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
@ -44,21 +46,17 @@ public class PocketBuilder
private PocketBuilder() { } private PocketBuilder() { }
private static boolean buildDungeonPocket(DungeonData dungeon, NewDimData dimension, DimLink link, DungeonSchematic schematic, World world, DDProperties properties) private static boolean buildDungeonPocket(DungeonData dungeon, NewDimData dimension, DimLink link, DungeonSchematic schematic, World world, DDProperties properties) {
{
//Calculate the destination point //Calculate the destination point
DungeonPackConfig packConfig = dungeon.dungeonType().Owner != null ? dungeon.dungeonType().Owner.getConfig() : null; DungeonPackConfig packConfig = dungeon.dungeonType().Owner != null ? dungeon.dungeonType().Owner.getConfig() : null;
Point4D source = link.source(); Point4D source = link.source();
int orientation = link.orientation(); EnumFacing orientation = link.orientation();
Point3D destination; BlockPos destination;
if (packConfig != null && packConfig.doDistortDoorCoordinates()) if (packConfig != null && packConfig.doDistortDoorCoordinates()) {
{
destination = calculateNoisyDestination(source, dimension, dungeon, orientation); destination = calculateNoisyDestination(source, dimension, dungeon, orientation);
} } else {
else destination = new BlockPos(source.getX(), source.getY(), source.getZ());
{
destination = new Point3D(source.getX(), source.getY(), source.getZ());
} }
destination.setY( yCoordHelper.adjustDestinationY(destination.getY(), world.getHeight(), schematic.getEntranceDoorLocation().getY(), schematic.getHeight()) ); destination.setY( yCoordHelper.adjustDestinationY(destination.getY(), world.getHeight(), schematic.getEntranceDoorLocation().getY(), schematic.getHeight()) );
@ -67,7 +65,7 @@ public class PocketBuilder
schematic.copyToWorld(world, destination, orientation, link, random, properties, false); schematic.copyToWorld(world, destination, orientation, link, random, properties, false);
//Finish up destination initialization //Finish up destination initialization
dimension.initializeDungeon(destination.getX(), destination.getY(), destination.getZ(), orientation, link, dungeon); dimension.initializeDungeon(destination, orientation, link, dungeon);
dimension.setFilled(true); dimension.setFilled(true);
return true; return true;
@ -160,7 +158,7 @@ public class PocketBuilder
} }
private static Point3D calculateNoisyDestination(Point4D source, NewDimData dimension, DungeonData dungeon, int orientation) private static BlockPos calculateNoisyDestination(Point4D source, NewDimData dimension, DungeonData dungeon, int orientation)
{ {
int depth = NewDimData.calculatePackDepth(dimension.parent(), dungeon); int depth = NewDimData.calculatePackDepth(dimension.parent(), dungeon);
int forwardNoise = MathHelper.getRandomIntegerInRange(random, 10 * depth, 130 * depth); int forwardNoise = MathHelper.getRandomIntegerInRange(random, 10 * depth, 130 * depth);
@ -169,9 +167,9 @@ public class PocketBuilder
//Rotate the link destination noise to point in the same direction as the door exit //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 //and add it to the door's location. Use EAST as the reference orientation since linkDestination
//is constructed as if pointing East. //is constructed as if pointing East.
Point3D linkDestination = new Point3D(forwardNoise, 0, sidewaysNoise); BlockPos linkDestination = new BlockPos(forwardNoise, 0, sidewaysNoise);
Point3D sourcePoint = new Point3D(source.getX(), source.getY(), source.getZ()); BlockPos sourcePoint = new BlockPos(source.getX(), source.getY(), source.getZ());
Point3D zeroPoint = new Point3D(0, 0, 0); BlockPos zeroPoint = new BlockPos(0, 0, 0);
BlockRotator.transformPoint(linkDestination, zeroPoint, orientation - BlockRotator.EAST_DOOR_METADATA, sourcePoint); BlockRotator.transformPoint(linkDestination, zeroPoint, orientation - BlockRotator.EAST_DOOR_METADATA, sourcePoint);
return linkDestination; return linkDestination;
} }
@ -450,8 +448,8 @@ public class PocketBuilder
} }
Point3D center = new Point3D(x - wallThickness + 1 + (size / 2), y - wallThickness - 1 + (size / 2), z); BlockPos center = new BlockPos(x - wallThickness + 1 + (size / 2), y - wallThickness - 1 + (size / 2), z);
Point3D door = new Point3D(x, y, z); BlockPos door = new BlockPos(x, y, z);
BlockRotator.transformPoint(center, door, orientation - BlockRotator.EAST_DOOR_METADATA, door); BlockRotator.transformPoint(center, door, orientation - BlockRotator.EAST_DOOR_METADATA, door);
//Build the outer layer of Eternal Fabric //Build the outer layer of Eternal Fabric

View file

@ -36,7 +36,7 @@ public abstract class BaseSchematicGateway extends BaseGateway
schematic.applyFilter(gatewayFilter); schematic.applyFilter(gatewayFilter);
schematic.applyImportFilters(properties); schematic.applyImportFilters(properties);
Point3D doorLocation = gatewayFilter.getEntranceDoorLocation(); BlockPos doorLocation = gatewayFilter.getEntranceDoorLocation();
int orientation = gatewayFilter.getEntranceOrientation(); int orientation = gatewayFilter.getEntranceOrientation();
// Build the gateway into the world // Build the gateway into the world

View file

@ -1,10 +1,10 @@
package com.zixiken.dimdoors.world.gateways; package com.zixiken.dimdoors.world.gateways;
import com.zixiken.dimdoors.Point3D;
import com.zixiken.dimdoors.DimDoors; import com.zixiken.dimdoors.DimDoors;
import com.zixiken.dimdoors.schematic.Schematic; import com.zixiken.dimdoors.schematic.Schematic;
import com.zixiken.dimdoors.schematic.SchematicFilter; import com.zixiken.dimdoors.schematic.SchematicFilter;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.util.BlockPos;
public class GatewayBlockFilter extends SchematicFilter { public class GatewayBlockFilter extends SchematicFilter {
@ -14,7 +14,7 @@ public class GatewayBlockFilter extends SchematicFilter {
private int entranceOrientation; private int entranceOrientation;
private Schematic schematic; private Schematic schematic;
private Point3D entranceDoorLocation; private BlockPos entranceDoorLocation;
public GatewayBlockFilter() public GatewayBlockFilter()
{ {
@ -28,7 +28,7 @@ public class GatewayBlockFilter extends SchematicFilter {
return entranceOrientation; return entranceOrientation;
} }
public Point3D getEntranceDoorLocation() { public BlockPos getEntranceDoorLocation() {
return entranceDoorLocation; return entranceDoorLocation;
} }