diff --git a/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index c0d9b37..b2e6388 100644 --- a/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -18,6 +18,11 @@ import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.DimensionManager; import StevenDimDoors.mod_pocketDim.DDProperties; +import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper; +import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor; +import StevenDimDoors.mod_pocketDim.schematic.BlockRotator; import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.world.PocketBuilder; import cpw.mods.fml.common.registry.GameRegistry; @@ -472,19 +477,63 @@ public class DDTeleporter return false; } - private static boolean generateSafeExit(NewDimData target, DimLink link, DDProperties properties) + private static boolean generateSafeExit(NewDimData destinationDim, DimLink link, DDProperties properties) { // A safe exit attempts to place a Warp Door in a dimension with // some precautions to protect the player. The X and Z coordinates - // are fixed to match the source, but the Y coordinate is chosen by - // searching for a safe location to place the door. The direction of - // the vertical search is away from the map boundary closest to - // the source Y. In other words, if a player is really high up, the - // search proceeds down. If a player is near the bottom of the map, - // the search proceeds up. If a safe destination cannot be found, - // then we return false and the source-side door slams shut. + // are fixed to match the source (mostly - may be shifted a little), + // but the Y coordinate is chosen by searching for a safe location + // to place the door. - // FIXME: Add code here! - return false; + // The direction of the vertical search is away from the map boundary + // closest to the source Y. In other words, if a player is really + // high up, the search goes down. If a player is near the bottom + // of the map, the search goes up. If a safe destination cannot be + // found, then we return false and the source-side door slams shut. + + Point3D destination; + Point4D source = link.source(); + World world = PocketManager.loadDimension(destinationDim.id()); + if (world == null) + { + return false; + } + + boolean searchDown = (source.getY() >= world.getActualHeight() / 2); + destination = yCoordHelper.findSafeCube(world, source.getX(), source.getY() - 2, source.getZ(), searchDown); + if (destination == null) + { + destination = yCoordHelper.findSafeCube(world, source.getX(), source.getY() - 2, source.getZ(), !searchDown); + } + if (destination != null) + { + // Set up a 3x3 platform at the destination + int x = destination.getX(); + int y = destination.getY(); + int z = destination.getZ(); + for (int dx = -1; dx <= 1; dx++) + { + for (int dz = -1; dz <= 1; dz++) + { + world.setBlock(x + dx, y, z + dz, properties.FabricBlockID); + } + } + + // Create a reverse link for returning + NewDimData sourceDim = PocketManager.getDimensionData(link.source().getDimension()); + DimLink reverse = destinationDim.createLink(x, y + 2, z, LinkTypes.REVERSE); + sourceDim.setDestination(reverse, source.getX(), source.getY(), source.getZ()); + + // Set up the warp door at the destination + int orientation = getDestinationOrientation(source, properties); + orientation = BlockRotator.transformMetadata(orientation, 2, properties.WarpDoorID); + ItemDimensionalDoor.placeDoorBlock(world, x, y + 1, z, orientation, mod_pocketDim.warpDoor); + + // Complete the link to the destination + // This comes last so the destination isn't set unless everything else works first + destinationDim.setDestination(link, x, y + 2, z); + } + + return (destination != null); } } diff --git a/StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java b/StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java index 1574634..d912b46 100644 --- a/StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java +++ b/StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java @@ -2,8 +2,10 @@ package StevenDimDoors.mod_pocketDim.helpers; import net.minecraft.block.Block; import net.minecraft.block.material.Material; +import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; +import StevenDimDoors.mod_pocketDim.Point3D; public class yCoordHelper { @@ -67,6 +69,76 @@ public class yCoordHelper material = block.blockMaterial; return (material.isLiquid() || !material.isReplaceable()); } + + public static Point3D findSafeCube(World world, int x, int startY, int z, boolean searchDown) + { + // Search for a 3x3x3 cube of air with blocks underneath + // We can also match against a 3x2x3 box with + // We shift the search area into the bounds of a chunk for the sake of simplicity, + // so that we don't need to worry about working across chunks. + + int localX = x < 0 ? (x % 16) + 16 : (x % 16); + int localZ = z < 0 ? (z % 16) + 16 : (z % 16); + int cornerX = x - localX; + int cornerZ = z - localZ; + localX = MathHelper.clamp_int(localX, 1, 14); + localZ = MathHelper.clamp_int(localZ, 1, 14); + + Chunk chunk = world.getChunkProvider().loadChunk(x >> 4, z >> 4); + + int layers = 0; + int height = world.getActualHeight(); + int y, dx, dz, blockID; + boolean filled; + Block block; + Point3D location = null; + + if (searchDown) + { + /*for (y = startY; y >= 0; y--) + { + blockID = chunk.getBlockID(localX, y, localZ); + + }*/ + } + else + { + // Check if a 3x3 layer of blocks is empty + // If we find a layer that contains replaceable blocks, it can + // serve as the base where we'll place the player and door. + for (y = Math.max(startY, 0); y < height; y++) + { + filled = false; + for (dx = -1; dx <= 1 && !filled; dx++) + { + for (dz = -1; dz <= 1 && !filled; dz++) + { + blockID = chunk.getBlockID(localX + dx, y, localZ + dz); + if (blockID != 0) + { + block = Block.blocksList[blockID]; + if (block != null && !block.blockMaterial.isReplaceable()) + { + filled = true; + } + layers = 0; + } + } + } + if (!filled) + { + layers++; + if (layers == 3) + { + location = new Point3D(localX + cornerX, y - 2, localZ + cornerZ); + break; + } + } + } + } + + return location; + } public static int adjustDestinationY(int y, int worldHeight, int entranceY, int dungeonHeight) {