From 07a5e2a64d87ef115f994852231bb7eea1685267 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sat, 7 Sep 2013 12:27:28 -0400 Subject: [PATCH] Progress on Rewrite Completed exit door code. Also fixed noise calculation for dungeon door destinations - we were attempting to use pack depth in the calculation before it had been initialized. --- .../mod_pocketDim/core/DDTeleporter.java | 60 ++++--- .../mod_pocketDim/core/NewDimData.java | 2 +- .../mod_pocketDim/helpers/yCoordHelper.java | 160 +++++++++++++----- .../mod_pocketDim/world/PocketBuilder.java | 6 +- 4 files changed, 164 insertions(+), 64 deletions(-) diff --git a/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index b2e6388..5f693c8 100644 --- a/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -30,7 +30,11 @@ import cpw.mods.fml.common.registry.GameRegistry; public class DDTeleporter { private static final Random random = new Random(); - private static int END_DIMENSION_ID = 1; + private static final int END_DIMENSION_ID = 1; + private static final int MAX_ROOT_SHIFT_CHANCE = 100; + private static final int START_ROOT_SHIFT_CHANCE = 0; + private static final int ROOT_SHIFT_CHANCE_PER_LEVEL = 5; + public static int cooldown = 0; private DDTeleporter() { } @@ -465,16 +469,26 @@ public class DDTeleporter // A dungeon exit acts the same as a safe exit, but has the chance of // taking the user to any non-pocket dimension, excluding Limbo and The End. + NewDimData current = PocketManager.getDimensionData(link.source.getDimension()); ArrayList roots = PocketManager.getRootDimensions(); - for (int attempts = 0; attempts < 10; attempts++) + int shiftChance = START_ROOT_SHIFT_CHANCE + ROOT_SHIFT_CHANCE_PER_LEVEL * (current.packDepth() - 1); + + if (random.nextInt(MAX_ROOT_SHIFT_CHANCE) < shiftChance) { - NewDimData selection = roots.get( random.nextInt(roots.size()) ); - if (selection.id() != END_DIMENSION_ID && selection.id() != properties.LimboDimensionID) + for (int attempts = 0; attempts < 10; attempts++) { - return generateSafeExit(selection, link, properties); + NewDimData selection = roots.get( random.nextInt(roots.size()) ); + if (selection.id() != END_DIMENSION_ID && + selection.id() != properties.LimboDimensionID && + selection != current.root()) + { + return generateSafeExit(selection, link, properties); + } } } - return false; + + // Yes, this could lead you back into Limbo. That's intentional. + return generateSafeExit(current.root(), link, properties); } private static boolean generateSafeExit(NewDimData destinationDim, DimLink link, DDProperties properties) @@ -482,16 +496,9 @@ public class DDTeleporter // 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 (mostly - may be shifted a little), - // but the Y coordinate is chosen by searching for a safe location - // to place the door. + // but the Y coordinate is chosen by searching for the nearest + // 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 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) @@ -499,11 +506,26 @@ public class DDTeleporter return false; } - boolean searchDown = (source.getY() >= world.getActualHeight() / 2); - destination = yCoordHelper.findSafeCube(world, source.getX(), source.getY() - 2, source.getZ(), searchDown); - if (destination == null) + int startY = source.getY() - 2; + Point3D destination; + Point3D locationUp = yCoordHelper.findSafeCubeUp(world, source.getX(), startY, source.getZ()); + Point3D locationDown = yCoordHelper.findSafeCubeDown(world, source.getX(), startY, source.getZ()); + + if (locationUp == null) { - destination = yCoordHelper.findSafeCube(world, source.getX(), source.getY() - 2, source.getZ(), !searchDown); + destination = locationDown; + } + else if (locationDown == null) + { + destination = locationUp; + } + else if (locationUp.getY() - startY <= startY - locationDown.getY()) + { + destination = locationUp; + } + else + { + destination = locationDown; } if (destination != null) { diff --git a/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 40fe18d..9e735aa 100644 --- a/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -447,7 +447,7 @@ public abstract class NewDimData this.packDepth = calculatePackDepth(parent, dungeon); } - private static int calculatePackDepth(NewDimData parent, DungeonData current) + public static int calculatePackDepth(NewDimData parent, DungeonData current) { DungeonData predecessor = parent.dungeon(); if (current == null) diff --git a/StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java b/StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java index d912b46..ec514e3 100644 --- a/StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java +++ b/StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java @@ -5,6 +5,7 @@ import net.minecraft.block.material.Material; import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunkProvider; import StevenDimDoors.mod_pocketDim.Point3D; public class yCoordHelper @@ -70,7 +71,7 @@ public class yCoordHelper return (material.isLiquid() || !material.isReplaceable()); } - public static Point3D findSafeCube(World world, int x, int startY, int z, boolean searchDown) + public static Point3D findSafeCubeUp(World world, int x, int startY, int z) { // Search for a 3x3x3 cube of air with blocks underneath // We can also match against a 3x2x3 box with @@ -84,62 +85,139 @@ public class yCoordHelper localX = MathHelper.clamp_int(localX, 1, 14); localZ = MathHelper.clamp_int(localZ, 1, 14); - Chunk chunk = world.getChunkProvider().loadChunk(x >> 4, z >> 4); + Chunk chunk = initializeChunkArea(world, x >> 4, z >> 4); - int layers = 0; int height = world.getActualHeight(); int y, dx, dz, blockID; - boolean filled; + boolean isSafe; Block block; - Point3D location = null; - - if (searchDown) + + // Initialize layers to a huge negative number so that we won't + // consider an area as usable unless it gets reset to 0 first + // when we find a foundation upon which to build. + int layers = -1000000; + + // 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 - 1, 0); y < height; y++) { - /*for (y = startY; y >= 0; y--) + isSafe = true; + for (dx = -1; dx <= 1 && isSafe; dx++) { - 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 && isSafe; dz++) { - for (dz = -1; dz <= 1 && !filled; dz++) + blockID = chunk.getBlockID(localX + dx, y, localZ + dz); + if (blockID != 0) { - blockID = chunk.getBlockID(localX + dx, y, localZ + dz); - if (blockID != 0) + block = Block.blocksList[blockID]; + if (!block.blockMaterial.isReplaceable()) { - block = Block.blocksList[blockID]; - if (block != null && !block.blockMaterial.isReplaceable()) - { - filled = true; - } - layers = 0; + isSafe = false; } - } - } - if (!filled) - { - layers++; - if (layers == 3) - { - location = new Point3D(localX + cornerX, y - 2, localZ + cornerZ); - break; + layers = 0; } } } + if (isSafe) + { + layers++; + if (layers == 3) + { + return new Point3D(localX + cornerX, y - 2, localZ + cornerZ); + } + } } - - return location; + return null; } + public static Point3D findSafeCubeDown(World world, int x, int startY, int z) + { + // 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 = initializeChunkArea(world, x >> 4, z >> 4); + + int height = world.getActualHeight(); + int y, dx, dz, blockID; + boolean isSafe; + boolean hasBlocks; + Block block; + int layers = 0; + + // 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.min(startY + 2, height - 1); y >= 0; y--) + { + isSafe = true; + hasBlocks = false; + for (dx = -1; dx <= 1 && isSafe; dx++) + { + for (dz = -1; dz <= 1 && isSafe; dz++) + { + blockID = chunk.getBlockID(localX + dx, y, localZ + dz); + if (blockID != 0) + { + block = Block.blocksList[blockID]; + if (!block.blockMaterial.isReplaceable()) + { + if (layers >= 3) + { + return new Point3D(localX + cornerX, y + 1, localZ + cornerZ); + } + isSafe = false; + } + hasBlocks = true; + } + } + } + if (isSafe) + { + layers++; + if (hasBlocks) + { + if (layers >= 3) + { + return new Point3D(localX + cornerX, y, localZ + cornerZ); + } + layers = 0; + } + } + } + return null; + } + + private static Chunk initializeChunkArea(World world, int chunkX, int chunkZ) + { + // We initialize a 3x3 area of chunks instead of just initializing + // the target chunk because things generated in adjacent chunks + // (e.g. trees) might intrude into the target chunk. + + IChunkProvider provider = world.getChunkProvider(); + Chunk target = provider.loadChunk(chunkX, chunkZ); + for (int dx = -1; dx <= 1; dx++) + { + for (int dz = -1; dz <= 1; dz++) + { + if (!provider.chunkExists(chunkX + dx, chunkZ + dz)) + { + provider.loadChunk(chunkX, chunkZ); + } + } + } + return target; + } + 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 diff --git a/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index 0f2d42f..0b55e71 100644 --- a/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -87,7 +87,7 @@ public class PocketBuilder if (packConfig != null && packConfig.doDistortDoorCoordinates()) { - destination = calculateNoisyDestination(source, dimension, orientation); + destination = calculateNoisyDestination(source, dimension, dungeon, orientation); } else { @@ -111,9 +111,9 @@ public class PocketBuilder } } - private static Point3D calculateNoisyDestination(Point4D source, NewDimData dimension, int orientation) + private static Point3D calculateNoisyDestination(Point4D source, NewDimData dimension, DungeonData dungeon, int orientation) { - int depth = dimension.packDepth(); + int depth = NewDimData.calculatePackDepth(dimension.parent(), dungeon); int forwardNoise = MathHelper.getRandomIntegerInRange(random, -50 * depth, 150 * depth); int sidewaysNoise = MathHelper.getRandomIntegerInRange(random, -10 * depth, 10 * depth);