diff --git a/src/main/java/StevenDimDoors/experimental/LinkPlan.java b/src/main/java/StevenDimDoors/experimental/LinkPlan.java index 3fe6f75..fbd90c1 100644 --- a/src/main/java/StevenDimDoors/experimental/LinkPlan.java +++ b/src/main/java/StevenDimDoors/experimental/LinkPlan.java @@ -1,52 +1,47 @@ package StevenDimDoors.experimental; +import StevenDimDoors.mod_pocketDim.Point3D; + public class LinkPlan { private RoomData source; private RoomData destination; - private boolean entrance; + private Point3D sourcePoint; + private Point3D destinationPoint; + private final boolean entrance; + private final boolean internal; - private LinkPlan(RoomData source, RoomData destination, boolean entrance) - { - this.source = source; - this.destination = destination; - this.entrance = entrance; - } - - public static LinkPlan createInternalLink(RoomData source, RoomData destination) + private LinkPlan(RoomData source, boolean entrance, boolean internal) { if (source == null) { throw new IllegalArgumentException("source cannot be null."); } - if (destination == null) - { - throw new IllegalArgumentException("destination cannot be null."); - } - LinkPlan plan = new LinkPlan(source, destination, false); + this.source = source; + this.destination = null; + this.sourcePoint = null; + this.destinationPoint = null; + this.entrance = entrance; + this.internal = internal; + } + + public static LinkPlan createInternalLink(RoomData source) + { + LinkPlan plan = new LinkPlan(source, false, true); source.getOutboundLinks().add(plan); - destination.getInboundLinks().add(plan); return plan; } public static LinkPlan createEntranceLink(RoomData source) { - if (source == null) - { - throw new IllegalArgumentException("source cannot be null."); - } - LinkPlan plan = new LinkPlan(source, null, true); + LinkPlan plan = new LinkPlan(source, true, false); source.getOutboundLinks().add(plan); return plan; } public static LinkPlan createDungeonLink(RoomData source) { - if (source == null) - { - throw new IllegalArgumentException("source cannot be null."); - } - LinkPlan plan = new LinkPlan(source, null, false); + LinkPlan plan = new LinkPlan(source, false, false); source.getOutboundLinks().add(plan); return plan; } @@ -68,7 +63,7 @@ public class LinkPlan public boolean isInternal() { - return (destination != null); + return internal; } public void remove() @@ -84,4 +79,42 @@ public class LinkPlan destination = null; } } + + public void setDestination(RoomData destination) + { + if (!internal) + { + throw new IllegalStateException("LinkPlan.setDestination() is only applicable to internal links."); + } + if (this.destination != null) + { + throw new IllegalStateException("destination can only be set once."); + } + if (destination == null) + { + throw new IllegalArgumentException("destination cannot be null."); + } + this.destination = destination; + destination.getInboundLinks().add(this); + } + + public Point3D sourcePoint() + { + return this.sourcePoint; + } + + public Point3D destinationPoint() + { + return this.destinationPoint; + } + + public void setSourcePoint(Point3D value) + { + this.sourcePoint = value; + } + + public void setDestinationPoint(Point3D value) + { + this.destinationPoint = value; + } } diff --git a/src/main/java/StevenDimDoors/experimental/MazeBuilder.java b/src/main/java/StevenDimDoors/experimental/MazeBuilder.java index 6505f99..760c399 100644 --- a/src/main/java/StevenDimDoors/experimental/MazeBuilder.java +++ b/src/main/java/StevenDimDoors/experimental/MazeBuilder.java @@ -1,18 +1,23 @@ package StevenDimDoors.experimental; +import java.util.ArrayList; import java.util.Random; +import java.util.Stack; import net.minecraft.block.Block; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.config.DDProperties; public class MazeBuilder { + private static final int POCKET_WALL_GAP = 4; + 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, DDProperties properties) { // ISSUE FOR LATER: The room needs to be shifted so as to be centered on its entrance @@ -22,16 +27,85 @@ public class MazeBuilder buildRooms(design.getLayout(), world, offset); carveDoorways(design.getLayout(), world, offset, decay, random); - - placeDoors(design.getLayout(), world, offset); - applyRandomDestruction(design, world, offset, decay, random); + decorateRooms(design.getLayout(), world, offset); + buildPocketWalls(design, world, offset, properties); } private static void applyRandomDestruction(MazeDesign design, World world, Point3D offset, SphereDecayOperation decay, Random random) { - //final int DECAY_BOX_SIZE = 8 + final int DECAY_BOX_SIZE = 7; + final int DECAY_OPERATIONS = 5 + random.nextInt(5); + final int DECAY_ATTEMPTS = 20; + + int x, y, z; + int successes = 0; + int attempts = 0; + PartitionNode root = design.getRootPartition(); + + for (; successes < DECAY_OPERATIONS && attempts < DECAY_ATTEMPTS; attempts++) + { + // Select the coordinates at which to apply the decay operation + x = random.nextInt(design.width()) - DECAY_BOX_SIZE / 2; + y = random.nextInt(design.height()) - DECAY_BOX_SIZE / 2; + z = random.nextInt(design.length()) - DECAY_BOX_SIZE / 2; + + // Check that the decay operation would not impact any protected areas + // and mark the affected areas as decayed + if (markDecayArea(x, y, z, DECAY_BOX_SIZE, root)) + { + // Apply decay + decay.apply(world, offset.getX() + x, offset.getY() + y, offset.getZ() + z, + DECAY_BOX_SIZE, DECAY_BOX_SIZE, DECAY_BOX_SIZE); + successes++; + } + } + } + + private static boolean markDecayArea(int x, int y, int z, int DECAY_BOX_SIZE, PartitionNode root) + { + // Check if a given PartitionNode intersects the decay area. If it's a leaf, then check + // if it's protected or not. Otherwise, check its children. The specific area is valid + // if and only if there are no protected rooms and at least one (unprotected) room in it. + // Also list the unprotected rooms to mark them if the decay operation will proceed. + + RoomData room; + PartitionNode partition; + ArrayList targets = new ArrayList(); + Stack> nodes = new Stack>(); + BoundingBox decayBounds = new BoundingBox(x, y, z, DECAY_BOX_SIZE, DECAY_BOX_SIZE, DECAY_BOX_SIZE); + + // Use depth-first search to explore all intersecting partitions + nodes.push(root); + while (!nodes.isEmpty()) + { + partition = nodes.pop(); + if (decayBounds.intersects(partition)) + { + if (partition.isLeaf()) + { + room = partition.getData(); + if (room.isProtected()) + return false; + targets.add(room); + } + else + { + if (partition.leftChild() != null) + nodes.push(partition.leftChild()); + if (partition.rightChild() != null) + nodes.push(partition.rightChild()); + } + } + } + // If execution has reached this point, then there were no protected rooms. + // Mark all intersecting rooms as decayed. + for (RoomData target : targets) + { + target.setDecayed(true); + } + return !targets.isEmpty(); } private static void buildRooms(DirectedGraph layout, World world, Point3D offset) @@ -43,19 +117,25 @@ public class MazeBuilder } } - private static void placeDoors(DirectedGraph layout, World world, Point3D offset) + private static void decorateRooms(DirectedGraph layout, World world, Point3D offset) { + RoomData room; + PartitionNode partition; + ArrayList links = new ArrayList(); + + // Iterate over all rooms and apply decorators for (IGraphNode node : layout.nodes()) { - RoomData room = node.data(); - Point3D minCorner = room.getPartitionNode().minCorner(); - if (!room.getOutboundLinks().isEmpty()) - { - setBlockDirectly(world, offset.getX() + minCorner.getX(), offset.getY() + minCorner.getY() + 1, - offset.getZ() + minCorner.getZ(), Block.glowStone.blockID, 0); - setBlockDirectly(world, offset.getX() + minCorner.getX(), offset.getY() + minCorner.getY() + 2, - offset.getZ() + minCorner.getZ(), Block.glowStone.blockID, 0); - } + room = node.data(); + partition = room.getPartitionNode(); + links.addAll(room.getOutboundLinks()); + + // TODO: Add decorator code here! + } + // Iterate over all links plans and place links in the world + for (LinkPlan link : links) + { + // TODO: Add link placement code here! } } @@ -70,12 +150,19 @@ public class MazeBuilder { for (IEdge passage : node.outbound()) { + // Carve out the passage doorway = passage.data(); axis = doorway.axis(); lower = doorway.minCorner(); carveDoorway(world, axis, offset.getX() + lower.getX(), offset.getY() + lower.getY(), offset.getZ() + lower.getZ(), doorway.width(), doorway.height(), doorway.length(), decay, random); + + // If this is a vertical passage, then mark the upper room as decayed + if (axis == DoorwayData.Y_AXIS) + { + passage.tail().data().setDecayed(true); + } } } } @@ -86,6 +173,8 @@ public class MazeBuilder final int MIN_DOUBLE_DOOR_SPAN = 10; int gap; + int rx; + int rz; switch (axis) { case DoorwayData.X_AXIS: @@ -150,9 +239,10 @@ public class MazeBuilder { gap = 6; } - decay.apply(world, - x + random.nextInt(width - gap - 1) + 1, y - 1, - z + random.nextInt(length - gap - 1) + 1, gap, 4, gap); + rx = x + random.nextInt(width - gap - 1) + 1; + rz = z + random.nextInt(length - gap - 1) + 1; + carveHole(world, rx + gap / 2, y, rz + gap / 2); + decay.apply(world, rx, y - 1, rz, gap, 4, gap); } else { @@ -184,6 +274,19 @@ public class MazeBuilder setBlockDirectly(world, x, y + 1, z, 0, 0); } + private static void buildPocketWalls(MazeDesign design, World world, Point3D offset, DDProperties properties) + { + // Build the inner Fabric of Reality box + Point3D minCorner = new Point3D(-POCKET_WALL_GAP - 1, -POCKET_WALL_GAP - 1, -POCKET_WALL_GAP - 1); + Point3D maxCorner = new Point3D(design.width() + POCKET_WALL_GAP, design.height() + POCKET_WALL_GAP, design.length() + POCKET_WALL_GAP); + buildBox(world, offset, minCorner, maxCorner, properties.FabricBlockID, 0); + + // Build the outer Eternal Fabric box + minCorner.add(-1, -1, -1); + maxCorner.add(1, 1, 1); + buildBox(world, offset, minCorner, maxCorner, properties.PermaFabricBlockID, 0); + } + private static void buildBox(World world, Point3D offset, Point3D minCorner, Point3D maxCorner, int blockID, int metadata) { int minX = minCorner.getX() + offset.getX(); diff --git a/src/main/java/StevenDimDoors/experimental/MazeDesign.java b/src/main/java/StevenDimDoors/experimental/MazeDesign.java index c88f1cd..16c190b 100644 --- a/src/main/java/StevenDimDoors/experimental/MazeDesign.java +++ b/src/main/java/StevenDimDoors/experimental/MazeDesign.java @@ -4,16 +4,16 @@ import java.util.ArrayList; public class MazeDesign { - private PartitionNode root; + private PartitionNode root; private DirectedGraph layout; - public MazeDesign(PartitionNode root, DirectedGraph layout) + public MazeDesign(PartitionNode root, DirectedGraph layout) { this.root = root; this.layout = layout; } - public PartitionNode getRootPartition() + public PartitionNode getRootPartition() { return root; } diff --git a/src/main/java/StevenDimDoors/experimental/MazeDesigner.java b/src/main/java/StevenDimDoors/experimental/MazeDesigner.java index 8707d46..53113cb 100644 --- a/src/main/java/StevenDimDoors/experimental/MazeDesigner.java +++ b/src/main/java/StevenDimDoors/experimental/MazeDesigner.java @@ -589,93 +589,180 @@ public class MazeDesigner // 3. Place internal links connecting the different sections of the maze // 4. Place more internal links to confuse people - // We need to start by counting the door capacity of each section and - // listing which rooms can have doors or destinations for each section. + // We need to start by building up data for each section, such as their + // door capacities and the rooms available for placing doors. int index; - int[] capacity = new int[cores.size()]; - ArrayList[] sourceRooms = (ArrayList[]) Array.newInstance(cores.getClass(), cores.size()); - ArrayList[] destinationRooms = (ArrayList[]) Array.newInstance(cores.getClass(), cores.size()); + int count; + SectionData selection; + SectionData destination; + ArrayList allSections; + ArrayList usableSections; - for (index = 0; index < sourceRooms.length; index++) - { - sourceRooms[index] = new ArrayList(); - destinationRooms[index] = new ArrayList(); - capacity[index] = listLinkRooms(cores.get(index).getLayoutNode(), sourceRooms[index], destinationRooms[index]); - } - - // Now we select the room in which to place the entrance. - // We can safely assume all source room lists are non-empty because - // createMazeSections() guarantees that each section has at least - // the capacity for 2 doors. - index = random.nextInt(sourceRooms.length); - createEntranceLink(sourceRooms[index], random.nextInt(sourceRooms[index].size())); - - // The next task is to place internal links. These links must connect - // the different maze sections to create a strongly connected graph. - - - } - - private static int listLinkRooms(IGraphNode core, - ArrayList sourceRooms, ArrayList destinationRooms) - { - int capacity = 0; - boolean hasHoles; - RoomData currentRoom; - IGraphNode current; - IGraphNode neighbor; - Stack> ordering = new Stack>(); - HashSet> visited = new HashSet>(); - - visited.add(core); - ordering.add(core); - while (!ordering.isEmpty()) - { - current = ordering.pop(); - hasHoles = false; - - for (IEdge edge : current.outbound()) + // Check if there is only one section. Our concerns differ depending + // on whether there is one or more than one. + if (cores.size() > 1) + { + // More than 1 section + allSections = new ArrayList(cores.size()); + for (RoomData core : cores) { - neighbor = edge.tail(); - if (visited.add(neighbor)) - { - ordering.add(neighbor); - } + allSections.add( SectionData.createFromCore(core.getLayoutNode()) ); } - for (IEdge edge : current.inbound()) + usableSections = (ArrayList) allSections.clone(); + + // Select the room in which to place the entrance. + // We can safely consider all sections because createMazeSections() + // guarantees that each one has at least the capacity for 2 doors. + // Remove the selected section if it falls below a capacity of 2 + // since we need to leave at least 1 capacity for section linking. + index = random.nextInt(usableSections.size()); + selection = usableSections.get(index); + selection.createEntranceLink(random); + if (selection.capacity() <= 1) { - neighbor = edge.head(); - if (visited.add(neighbor)) + usableSections.remove(index); + } + + // Place 3 to 4 dungeon doors in random sections + // Remove any sections that fall under a capacity of 2. + count = 3 + random.nextInt(2); + for (; count > 0 && !usableSections.isEmpty(); count--) + { + index = random.nextInt(usableSections.size()); + selection = usableSections.get(index); + selection.createDungeonLink(random); + if (selection.capacity() <= 1) { - ordering.add(neighbor); - } - if (edge.data().axis() == DoorwayData.Y_AXIS) - { - hasHoles = true; + usableSections.remove(index); } } - if (!hasHoles) + // The next task is to place internal links. These links must connect + // the different maze sections to create a strongly connected graph. + linkMazeSections(allSections, random); + + // Add 1 to 3 extra internal links to confuse people + usableSections.clear(); + for (SectionData section : allSections) { - currentRoom = current.data(); - destinationRooms.add(currentRoom); - if (currentRoom.estimateDoorCapacity() > 0) + if (section.capacity() > 0) { - capacity += currentRoom.estimateDoorCapacity(); - sourceRooms.add(currentRoom); + usableSections.add(section); + } + } + count = 1 + random.nextInt(3); + for (; count > 0 && !usableSections.isEmpty(); count--) + { + index = random.nextInt(usableSections.size()); + selection = usableSections.get(index); + destination = allSections.get( random.nextInt(allSections.size()) ); + selection.reserveSectionLink(destination, random); + if (selection.capacity() == 0) + { + usableSections.remove(index); + } + } + + // Finally, make sure to process all reservations for section links. + for (SectionData section : allSections) + { + section.processReservedLinks(random); + } + } + else + { + // Only 1 section + selection = SectionData.createFromCore(cores.get(0).getLayoutNode()); + // Place entrance door in a random room + selection.createEntranceLink(random); + // Place 3 to 4 dungeon doors or fewer, based on capacity + count = Math.min(3 + random.nextInt(2), selection.capacity()); + for (; count > 0; count--) + { + selection.createDungeonLink(random); + } + } + } + + private static void linkMazeSections(ArrayList sections, Random random) + { + // This algorithm constructs links sections together using Dimensional Doors + // to create a random strongly connected graph. It takes into account capacity + // constraints as well. We assume that all sections have at least 1 door capacity. + final int EXTENSION_CHANCE = 2; + final int MAX_EXTENSION_CHANCE = 3; + + int index; + SectionData start; + SectionData current; + SectionData next; + + // Total spare capacity of the sections not in "remaining" + int capacity; + // Sections not in the graph + ArrayList remaining = (ArrayList) sections.clone(); + // Sections that are part of an incomplete cycle + ArrayList attached = new ArrayList(sections.size()); + // Sections that are part of a cycle and thus strongly connected + ArrayList connected = new ArrayList(sections.size()); + // Sections that are part of a cycle and have spare capacity - used to start new cycles + ArrayList starters = new ArrayList(sections.size()); + + // Shuffle remaining to achieve randomness + Collections.shuffle(remaining, random); + // Remove the starting node to serve as the base of our strongly connected graph + start = remaining.remove(remaining.size() - 1); + starters.add(start); + connected.add(start); + capacity = start.capacity(); + + // Repeat until all sections are connected + while (!remaining.isEmpty()) + { + // Select a section from which to start a new cycle + index = random.nextInt(starters.size()); + start = starters.get(index); + // Select the first new section in the cycle and link to it + current = remaining.remove(remaining.size() - 1); + attached.add(current); + start.reserveSectionLink(current, random); + // Add the current section's capacity to the total, but subtract two to account + // for the link just created and for the future link from this section to another + capacity += current.capacity() - 2; + // Remove the starting section from starters if it has exhausted its capacity + if (start.capacity() == 0) + { + starters.remove(index); + } + + // Continue attaching sections to the partial cycle while there are are still sections + // left to be added and we have no spare capacity. Or we could randomly decide to + // continue even with spare capacity. Spare capacity means we could start a new cycle + // safely and still achieve strong connectivity. Randomness here influences the kinds + // of graphs we can get. + while (!remaining.isEmpty() && (capacity == 0 || + random.nextInt(MAX_EXTENSION_CHANCE) < EXTENSION_CHANCE)) + { + next = remaining.remove(remaining.size() - 1); + attached.add(next); + current.reserveSectionLink(next, random); + // Account for this section's capacity, but subtract one for + // the future link that will connect this section to another + capacity += next.capacity() - 1; + current = next; + } + next = connected.get(random.nextInt(connected.size())); + current.reserveSectionLink(next, random); + for (SectionData section : attached) + { + connected.add(section); + if (section.capacity() > 0) + { + starters.add(section); } } } - return capacity; - } - - private static void createEntranceLink(ArrayList sources, int index) - { - RoomData entranceRoom = sources.get(index); - LinkPlan.createEntranceLink(entranceRoom); - if (entranceRoom.getRemainingDoorCapacity() == 0) - { - sources.remove(index); - } + + // Done! At this point, all sections are connected. } } diff --git a/src/main/java/StevenDimDoors/experimental/SectionData.java b/src/main/java/StevenDimDoors/experimental/SectionData.java new file mode 100644 index 0000000..22d240a --- /dev/null +++ b/src/main/java/StevenDimDoors/experimental/SectionData.java @@ -0,0 +1,192 @@ +package StevenDimDoors.experimental; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Random; +import java.util.Stack; + +public class SectionData +{ + // Specifies the chance of selecting a destination from protectedRooms + // rather than from destinationRooms (which will then become protected) + private static final int PROTECTED_DESTINATION_CHANCE = 4; + private static final int MAX_PROTECTED_DESTINATION_CHANCE = 5; + + private int capacity; + private ArrayList sourceRooms; + private ArrayList protectedRooms; + private ArrayList destinationRooms; + private ArrayList reservations; + + private SectionData(ArrayList sourceRooms, ArrayList destinationRooms, int capacity) + { + this.capacity = capacity; + this.sourceRooms = sourceRooms; + this.destinationRooms = destinationRooms; + this.protectedRooms = new ArrayList(); + this.reservations = new ArrayList(); + } + + public static SectionData createFromCore(IGraphNode core) + { + int capacity = 0; + ArrayList sourceRooms = new ArrayList(); + ArrayList destinationRooms = new ArrayList(); + + boolean hasHoles; + RoomData currentRoom; + IGraphNode current; + IGraphNode neighbor; + Stack> ordering = new Stack>(); + HashSet> visited = new HashSet>(); + + visited.add(core); + ordering.add(core); + while (!ordering.isEmpty()) + { + current = ordering.pop(); + hasHoles = false; + + for (IEdge edge : current.outbound()) + { + neighbor = edge.tail(); + if (visited.add(neighbor)) + { + ordering.add(neighbor); + } + } + for (IEdge edge : current.inbound()) + { + neighbor = edge.head(); + if (visited.add(neighbor)) + { + ordering.add(neighbor); + } + if (edge.data().axis() == DoorwayData.Y_AXIS) + { + hasHoles = true; + } + } + + if (!hasHoles) + { + currentRoom = current.data(); + destinationRooms.add(currentRoom); + if (currentRoom.estimateDoorCapacity() > 0) + { + capacity += currentRoom.estimateDoorCapacity(); + sourceRooms.add(currentRoom); + } + } + } + return new SectionData(sourceRooms, destinationRooms, capacity); + } + + public int capacity() + { + return capacity; + } + + public void createEntranceLink(Random random) + { + int index = random.nextInt(sourceRooms.size()); + RoomData room = sourceRooms.get(index); + LinkPlan.createEntranceLink(room); + if (room.getRemainingDoorCapacity() == 0) + { + sourceRooms.remove(index); + } + // It's okay to check containment in this list because + // the number of protected rooms is expected to be small + if (!protectedRooms.contains(room)) + { + protectedRooms.add(room); + } + capacity--; + } + + public void createDungeonLink(Random random) + { + int index = random.nextInt(sourceRooms.size()); + RoomData room = sourceRooms.get(index); + LinkPlan.createDungeonLink(room); + if (room.getRemainingDoorCapacity() == 0) + { + sourceRooms.remove(index); + } + // It's okay to check containment in this list because + // the number of protected rooms is expected to be small + if (!protectedRooms.contains(room)) + { + protectedRooms.add(room); + } + capacity--; + } + + public void reserveSectionLink(SectionData destination, Random random) + { + // This method "reserves" a link by decrementing the capacity of this + // section and assigning a source room to the link. However, assigning + // its destination in a particular section is deferred. Why? + + // We favor using source rooms as destinations to cut down the number + // of rooms that have to be marked as protected against decay effects. + // We defer assigning a destination until after all source rooms are + // known so that we have that information available. Otherwise, + // destination selection would be biased toward non-source rooms and + // rooms with dungeon doors, which are placed before section links. + + int index = random.nextInt(sourceRooms.size()); + RoomData room = sourceRooms.get(index); + destination.reserveDestination(LinkPlan.createInternalLink(room)); + if (room.getRemainingDoorCapacity() == 0) + { + sourceRooms.remove(index); + } + // It's okay to check containment in this list because + // the number of protected rooms is expected to be small + if (!protectedRooms.contains(room)) + { + protectedRooms.add(room); + } + capacity--; + } + + public void processReservedLinks(Random random) + { + for (LinkPlan link : reservations) + { + link.setDestination( getLinkDestination(random) ); + } + reservations.clear(); + } + + private void reserveDestination(LinkPlan link) + { + reservations.add(link); + } + + private RoomData getLinkDestination(Random random) + { + RoomData destination; + + // Choose whether to select a room that is already protected or select + // from all possible destination rooms. Note that some destination rooms + // may also be protected rooms already. + if (random.nextInt(MAX_PROTECTED_DESTINATION_CHANCE) < PROTECTED_DESTINATION_CHANCE) + { + destination = protectedRooms.get( random.nextInt(protectedRooms.size()) ); + } + else + { + destination = destinationRooms.get( random.nextInt(destinationRooms.size()) ); + // It's okay to check containment in this list because + // the number of protected rooms is expected to be small + if (!protectedRooms.contains(destination)) + { + protectedRooms.add(destination); + } + } + return destination; + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/Point3D.java b/src/main/java/StevenDimDoors/mod_pocketDim/Point3D.java index f639ce1..627bdab 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/Point3D.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/Point3D.java @@ -55,6 +55,13 @@ public class Point3D implements Serializable { { return this.z = z; } + + public void add(int x, int y, int z) + { + this.x += x; + this.y += y; + this.z += z; + } @Override public Point3D clone() diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index 913c282..462033a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -477,7 +477,7 @@ public class PocketBuilder } */ - MazeBuilder.generate(world, x, y, z, random); + MazeBuilder.generate(world, x, y, z, random, properties); //Build the door int doorOrientation = BlockRotator.transformMetadata(BlockRotator.EAST_DOOR_METADATA, orientation - BlockRotator.EAST_DOOR_METADATA + 2, properties.DimensionalDoorID);