diff --git a/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 543ffba0..f8c9941c 100644 --- a/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -9,6 +9,7 @@ import java.util.TreeMap; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.dungeon.DungeonData; +import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; import StevenDimDoors.mod_pocketDim.util.Point4D; public abstract class NewDimData implements Serializable @@ -460,6 +461,39 @@ public abstract class NewDimData implements Serializable this.origin = link.destination(); this.orientation = orientation; this.dungeon = dungeon; + this.packDepth = calculatePackDepth(parent, dungeon); + } + + private static int calculatePackDepth(NewDimData parent, DungeonData current) + { + DungeonData predecessor = parent.dungeon(); + if (current == null) + { + throw new IllegalArgumentException("current cannot be null."); + } + if (predecessor == null) + { + return 1; + } + + DungeonPack predOwner = predecessor.dungeonType().Owner; + DungeonPack currentOwner = current.dungeonType().Owner; + if (currentOwner == null) + { + return 1; + } + if (predOwner == null) + { + return 1; + } + if (predOwner == currentOwner) + { + return parent.packDepth + 1; + } + else + { + return 1; + } } public void initializePocket(int originX, int originY, int originZ, int orientation, IDimLink link) diff --git a/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java b/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java index ecfb71a8..ab6013a9 100644 --- a/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java +++ b/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java @@ -167,15 +167,14 @@ public class DungeonSchematic extends Schematic { return new DungeonSchematic(Schematic.copyFromWorld(world, x, y, z, width, height, length, doCompactBounds)); } - public void copyToWorld(World world, Point3D pocketCenter, int dungeonOrientation, IDimLink entryLink) + public void copyToWorld(World world, Point3D pocketCenter, int dungeonOrientation, IDimLink entryLink, Random random) { //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, //then just use that support from DungeonSchematic instead of making this local fix. //It might be easiest to support transformations using a WorldOperation - final int turnAngle = dungeonOrientation - orientation; - + final int turnAngle = dungeonOrientation - orientation; int index; int count; @@ -222,18 +221,11 @@ public class DungeonSchematic extends Schematic { world.setBlockTileEntity(pocketPoint.getX(), pocketPoint.getY(), pocketPoint.getZ(), TileEntity.createAndLoadEntity(tileTag)); } - setUpDungeon(PocketManager.getDimensionData(world), world, pocketCenter, turnAngle, entryLink); + setUpDungeon(PocketManager.getDimensionData(world), world, pocketCenter, turnAngle, entryLink, random); } - private void setUpDungeon(NewDimData dimension, World world, Point3D pocketCenter, int turnAngle, IDimLink entryLink) + private void setUpDungeon(NewDimData dimension, World world, Point3D pocketCenter, int turnAngle, IDimLink entryLink, Random random) { - //The following Random initialization code is based on code from ChunkProviderGenerate. - //It makes our generation depend on the world seed. - Random random = new Random(world.getSeed()); - long factorA = random.nextLong() / 2L * 2L + 1L; - long factorB = random.nextLong() / 2L * 2L + 1L; - random.setSeed(pocketCenter.getX() * factorB + pocketCenter.getZ() * factorA ^ world.getSeed()); - //Transform dungeon corners Point3D minCorner = new Point3D(0, 0, 0); Point3D maxCorner = new Point3D(width - 1, height - 1, length - 1); diff --git a/StevenDimDoors/mod_pocketDim/util/Pair.java b/StevenDimDoors/mod_pocketDim/util/Pair.java new file mode 100644 index 00000000..7e5f341d --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/util/Pair.java @@ -0,0 +1,26 @@ +package StevenDimDoors.mod_pocketDim.util; + +public class Pair +{ + //Pair is an implementation of a 2-tuple with generic parameters for strongly-typed elements. + //It's used instead of Minecraft's Tuple type because Tuple doesn't have strongly-typed elements. + + private P first; + private Q second; + + public Pair(P first, Q second) + { + this.first = first; + this.second = second; + } + + public P getFirst() + { + return first; + } + + public Q getSecond() + { + return second; + } +} diff --git a/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index e880ce61..cc524fde 100644 --- a/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -1,9 +1,9 @@ package StevenDimDoors.mod_pocketDim.world; -import java.util.HashMap; import java.util.Random; import net.minecraft.block.Block; +import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; @@ -19,6 +19,7 @@ import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPackConfig; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper; import StevenDimDoors.mod_pocketDim.schematic.BlockRotator; +import StevenDimDoors.mod_pocketDim.util.Pair; import StevenDimDoors.mod_pocketDim.util.Point4D; public class PocketBuilder @@ -35,25 +36,6 @@ public class PocketBuilder private PocketBuilder() { } - public static boolean initializeDestination(IDimLink link, DDProperties properties) - { - if (link.hasDestination()) - { - return true; - } - - //Check the destination type and respond accordingly - switch (link.linkType()) - { - case IDimLink.TYPE_DUNGEON: - return generateNewDungeonPocket(link, properties); - case IDimLink.TYPE_POCKET: - return generateNewPocket(link, properties); - default: - throw new IllegalArgumentException("link has an unrecognized link type."); - } - } - public static boolean generateNewDungeonPocket(IDimLink link, DDProperties properties) { if (link == null) @@ -93,31 +75,35 @@ public class PocketBuilder return false; } - /* This code is currently wrong. It's missing the following things: - * 1. Calculate the destination point for real. That includes adding door noise if needed. - * 2. Receive the DungeonData from selectDungeon() - * 3. The function signature for DungeonSchematic.copyToWorld() has to be rewritten. - */ - //Choose a dungeon to generate - DungeonSchematic schematic = selectDungeon(dimension, random, properties); - - if (schematic == null) + Pair pair = selectDungeon(dimension, random, properties); + if (pair == null) { System.err.println("Could not select a dungeon for generation!"); return false; } + DungeonData dungeon = pair.getFirst(); + DungeonSchematic schematic = pair.getSecond(); //Calculate the destination point + DungeonPackConfig packConfig = dungeon.dungeonType().Owner != null ? dungeon.dungeonType().Owner.getConfig() : null; Point4D source = link.source(); - int destinationY = yCoordHelper.adjustDestinationY(destination, world.getHeight(), schematic.getEntranceDoorLocation().getY(), schematic.getHeight()); - int orientation = getDestinationOrientation(source); - destination.setY(destinationY); + int orientation = getDoorOrientation(source, properties); + Point3D destination; + + if (packConfig != null && packConfig.doDistortDoorCoordinates()) + { + destination = calculateNoisyDestination(source, dimension, orientation); + } + else + { + destination = new Point3D(source.getX(), source.getY(), source.getZ()); + } + + destination.setY( yCoordHelper.adjustDestinationY(destination.getY(), world.getHeight(), schematic.getEntranceDoorLocation().getY(), schematic.getHeight()) ); //Generate the dungeon - DungeonPackConfig packConfig = dungeon.dungeonType().Owner != null ? dungeon.dungeonType().Owner.getConfig() : null; - - schematic.copyToWorld(world, link, packConfig.doDistortDoorCoordinates()); + schematic.copyToWorld(world, destination, orientation, link, random); //Finish up destination initialization dimension.initializePocket(destination.getX(), destination.getY(), destination.getZ(), orientation, link); @@ -131,7 +117,23 @@ public class PocketBuilder } } - private static DungeonSchematic selectDungeon(NewDimData dimension, Random random, DDProperties properties) + private static Point3D calculateNoisyDestination(Point4D source, NewDimData dimension, int orientation) + { + int depth = dimension.packDepth(); + int forwardNoise = MathHelper.getRandomIntegerInRange(random, -50 * depth, 150 * depth); + int sidewaysNoise = MathHelper.getRandomIntegerInRange(random, -10 * depth, 10 * depth); + + //Rotate the link destination noise to point in the same direction as the door exit + //and add it to the door's location. Use EAST as the reference orientation since linkDestination + //is constructed as if pointing East. + Point3D linkDestination = new Point3D(forwardNoise, 0, sidewaysNoise); + Point3D sourcePoint = new Point3D(source.getX(), source.getY(), source.getZ()); + Point3D zeroPoint = new Point3D(0, 0, 0); + BlockRotator.transformPoint(linkDestination, zeroPoint, orientation - BlockRotator.EAST_DOOR_METADATA, sourcePoint); + return linkDestination; + } + + private static Pair selectDungeon(NewDimData dimension, Random random, DDProperties properties) { //We assume the dimension doesn't have a dungeon assigned if (dimension.dungeon() != null) @@ -157,7 +159,6 @@ public class PocketBuilder { //TODO: In the future, remove this dungeon from the generation lists altogether. //That will have to wait until our code is updated to support that more easily. - try { System.err.println("Loading the default error dungeon instead..."); @@ -170,7 +171,7 @@ public class PocketBuilder return null; } } - return schematic; + return new Pair(dungeon, schematic); } private static DungeonSchematic loadAndValidateDungeon(DungeonData dungeon, DDProperties properties) @@ -218,10 +219,25 @@ public class PocketBuilder return generateNewPocket(link, DEFAULT_POCKET_SIZE, DEFAULT_POCKET_WALL_THICKNESS, properties); } - private static int getDestinationOrientation(Point4D source) + private static int getDoorOrientation(Point4D source, DDProperties properties) { - // TODO Auto-generated method stub - return 0; + World world = DimensionManager.getWorld(source.getDimension()); + if (world == null) + { + throw new IllegalStateException("The link's source world should be loaded!"); + } + + //Check if the block at that point is actually a door + int blockID = world.getBlockId(source.getX(), source.getY(), source.getZ()); + if (blockID != properties.DimensionalDoorID && blockID != properties.WarpDoorID && + blockID != properties.TransientDoorID) + { + throw new IllegalStateException("The link's source is not a door block. It should be impossible to traverse a rift without a door!"); + } + + //Return the orientation portion of its metadata + int orientation = world.getBlockMetadata(source.getX(), source.getY(), source.getZ()) & 3; + return orientation; } public static boolean generateNewPocket(IDimLink link, int size, int wallThickness, DDProperties properties) @@ -283,7 +299,7 @@ public class PocketBuilder //Calculate the destination point Point4D source = link.source(); int destinationY = yCoordHelper.adjustDestinationY(source.getY(), world.getHeight(), wallThickness + 1, size); - int orientation = getDestinationOrientation(source); + int orientation = getDoorOrientation(source, properties); //Build the actual pocket area buildPocket(world, source.getX(), destinationY, source.getZ(), orientation, size, wallThickness, properties);