diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index d3b09f46..f52fa181 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -40,7 +40,7 @@ public class EventHookContainer } @ForgeSubscribe(priority = EventPriority.LOW) - public void onMapGen(InitMapGenEvent event) + public void onInitMapGen(InitMapGenEvent event) { // Replace the Nether fortress generator with our own only if any gateways would ever generate. // This allows admins to disable our fortress overriding without disabling all gateways. @@ -81,42 +81,46 @@ public class EventHookContainer @ForgeSubscribe public void onPlayerEvent(PlayerInteractEvent event) { - //Handle placement of vanilla doors on rifts - if(!event.entity.worldObj.isRemote) + // Handle placing Vanilla doors on rifts + if (!event.entity.worldObj.isRemote) { World world = event.entity.worldObj; - ItemStack item = event.entityPlayer.inventory.getCurrentItem(); - if(item!=null) + ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); + if (stack != null) { - if(item.getItem() instanceof ItemDoor&&!(item.getItem() instanceof BaseItemDoor)) + Item item = stack.getItem(); + if (item instanceof ItemDoor) { Block doorToPlace = null; - if(item.itemID == Item.doorIron.itemID) + if (stack.itemID == Item.doorIron.itemID) { - doorToPlace =mod_pocketDim.dimensionalDoor; + doorToPlace = mod_pocketDim.dimensionalDoor; } - else if(item.itemID == Item.doorWood.itemID) + else if (stack.itemID == Item.doorWood.itemID) { - doorToPlace =mod_pocketDim.warpDoor; + doorToPlace = mod_pocketDim.warpDoor; } - else if(item.itemID == mod_pocketDim.itemGoldenDoor.itemID) + else if (stack.itemID == mod_pocketDim.itemGoldenDoor.itemID) { - doorToPlace =mod_pocketDim.goldenDimensionalDoor; + doorToPlace = mod_pocketDim.goldenDimensionalDoor; } - if(((BaseItemDoor) mod_pocketDim.itemDimensionalDoor).tryPlacingDoor(doorToPlace, world, event.entityPlayer,item)) + + if (doorToPlace != null) { - if(!event.entityPlayer.capabilities.isCreativeMode) - { - item.stackSize--; - } - if(!event.entity.worldObj.isRemote) + // SenseiKiwi: Why do we have a condition like this? And the event isn't cancelled if we take the else portion. + // Comments would have been very helpful. + if (mod_pocketDim.itemDimensionalDoor.tryPlacingDoor(doorToPlace, world, event.entityPlayer, stack)) { + if (!event.entityPlayer.capabilities.isCreativeMode) + { + stack.stackSize--; + } event.setCanceled(true); } - } - else - { - BaseItemDoor.tryItemUse(doorToPlace, item, event.entityPlayer, world, event.x, event.y, event.z, event.face, true, true); + else + { + BaseItemDoor.tryItemUse(doorToPlace, stack, event.entityPlayer, world, event.x, event.y, event.z, event.face, true, true); + } } } } @@ -197,8 +201,7 @@ public class EventHookContainer player.extinguish(); player.clearActivePotions(); player.setHealth(player.getMaxHealth()); - ChunkCoordinates coords = LimboProvider.getLimboSkySpawn(player.worldObj.rand); - Point4D destination = new Point4D((int) (coords.posX + player.posX), coords.posY, (int) (coords.posZ + player.posZ ), mod_pocketDim.properties.LimboDimensionID); + Point4D destination = LimboProvider.getLimboSkySpawn(player, properties); DDTeleporter.teleportEntity(player, destination, false); } @@ -218,24 +221,29 @@ public class EventHookContainer public void playMusicForDim(World world) { - if(world.isRemote) + if (world.isRemote) { SoundManager sndManager = FMLClientHandler.instance().getClient().sndManager; - if(world.provider instanceof LimboProvider) - { - sndManager.sndSystem.stop("BgMusic"); - SoundPoolEntry soundPoolEntry = sndManager.soundPoolSounds.getRandomSoundFromSoundPool(mod_pocketDim.modid+":creepy"); - if(soundPoolEntry!=null) - { - sndManager.sndSystem.backgroundMusic("LimboMusic", soundPoolEntry.getSoundUrl(), soundPoolEntry.getSoundName(), false); - sndManager.sndSystem.play("LimboMusic"); - } - } - else if(!(world.provider instanceof LimboProvider)) - { - sndManager.sndSystem.stop("LimboMusic"); - } + // SenseiKiwi: I've added the following check as a quick fix for a reported crash. + // This needs to work without a hitch or we have to stop trying to replace the background music... + if (sndManager != null && sndManager.sndSystem != null) + { + if (world.provider instanceof LimboProvider) + { + sndManager.sndSystem.stop("BgMusic"); + SoundPoolEntry soundPoolEntry = sndManager.soundPoolSounds.getRandomSoundFromSoundPool(mod_pocketDim.modid+":creepy"); + if (soundPoolEntry != null) + { + sndManager.sndSystem.backgroundMusic("LimboMusic", soundPoolEntry.getSoundUrl(), soundPoolEntry.getSoundName(), false); + sndManager.sndSystem.play("LimboMusic"); + } + } + else if (!(world.provider instanceof LimboProvider)) + { + sndManager.sndSystem.stop("LimboMusic"); + } + } } } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java index cc15c9f6..ada00b6f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java @@ -43,8 +43,8 @@ public class BlockRift extends Block implements ITileEntityProvider private static final int BLOCK_SEARCH_CHANCE = 50; private static final int MAX_BLOCK_DESTRUCTION_CHANCE = 100; private static final int BLOCK_DESTRUCTION_CHANCE = 50; - private static final int WORLD_THREAD_CHANCE = 5; - private static final int MAX_WORLD_THREAD_CHANCE = 100; + + public static final int MAX_WORLD_THREAD_DROP_CHANCE = 1000; private final DDProperties properties; private final ArrayList blocksImmuneToRift; @@ -173,7 +173,7 @@ public class BlockRift extends Block implements ITileEntityProvider { if (random.nextInt(MAX_BLOCK_DESTRUCTION_CHANCE) < BLOCK_DESTRUCTION_CHANCE) { - spawnWorldThread(world.getBlockId(target.getX(), target.getY(), target.getZ()), world, x, y, z, random); + dropWorldThread(world.getBlockId(target.getX(), target.getY(), target.getZ()), world, x, y, z, random); world.destroyBlock(target.getX(), target.getY(), target.getZ(), false); } } @@ -220,9 +220,9 @@ public class BlockRift extends Block implements ITileEntityProvider return targets; } - private void spawnWorldThread(int blockID, World world, int x, int y, int z, Random random) + private void dropWorldThread(int blockID, World world, int x, int y, int z, Random random) { - if (blockID != 0 && (random.nextInt(MAX_WORLD_THREAD_CHANCE) < WORLD_THREAD_CHANCE) + if (blockID != 0 && (random.nextInt(MAX_WORLD_THREAD_DROP_CHANCE) < properties.WorldThreadDropChance) && !(Block.blocksList[blockID] instanceof BlockFlowing || Block.blocksList[blockID] instanceof BlockFluid || Block.blocksList[blockID] instanceof IFluidBlock)) @@ -258,7 +258,7 @@ public class BlockRift extends Block implements ITileEntityProvider { int blockID = world.getBlockId(x, y, z); if (world.setBlock(x, y, z, properties.RiftBlockID)) - spawnWorldThread(blockID, world, x, y, z, random); + dropWorldThread(blockID, world, x, y, z, random); } } @@ -284,7 +284,7 @@ public class BlockRift extends Block implements ITileEntityProvider if (world.setBlock(x, y, z, properties.RiftBlockID)) { dimension.createChildLink(x, y, z, parent); - spawnWorldThread(blockID, world, x, y, z, random); + dropWorldThread(blockID, world, x, y, z, random); return true; } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java index d5ba8dde..b1512e3a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java @@ -63,15 +63,24 @@ public class CommandCreateDungeonRift extends DDCommandBase { result = findDungeonByPartialName(command[0], dungeonHelper.getUntaggedDungeons()); } - //Check if we found any matches + + // Check if we found any matches if (result != null) { - //Create a rift to our selected dungeon and notify the player dimension = PocketManager.getDimensionData(sender.worldObj); link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); - PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, result); - sender.worldObj.setBlock(x, y + 1, z, mod_pocketDim.blockRift.blockID, 0, 3); - sendChat(sender, "Created a rift to \"" + result.schematicName() + "\" dungeon (Dimension ID = " + link.destination().getDimension() + ")."); + if (PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, result)) + { + // Create a rift to our selected dungeon and notify the player + sender.worldObj.setBlock(x, y + 1, z, mod_pocketDim.blockRift.blockID, 0, 3); + sendChat(sender, "Created a rift to \"" + result.schematicName() + "\" dungeon (Dimension ID = " + link.destination().getDimension() + ")."); + } + else + { + // Dungeon generation failed somehow. Notify the user and remove the useless link. + dimension.deleteLink(link); + sendChat(sender, "Dungeon generation failed unexpectedly!"); + } } else { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java index 013921b2..97cc1a59 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java @@ -69,15 +69,24 @@ public class CommandCreateRandomRift extends DDCommandBase { result = getRandomDungeonByPartialName(command[0], dungeonHelper.getUntaggedDungeons()); } - //Check if we found any matches + + // Check if we found any matches if (result != null) { - //Create a rift to our selected dungeon and notify the player dimension = PocketManager.getDimensionData(sender.worldObj); link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); - PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, result); - sender.worldObj.setBlock(x, y + 1, z, mod_pocketDim.blockRift.blockID, 0, 3); - sendChat(sender, "Created a rift to \"" + result.schematicName() + "\" dungeon (Dimension ID = " + link.destination().getDimension() + ")."); + if (PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, result)) + { + // Create a rift to our selected dungeon and notify the player + sender.worldObj.setBlock(x, y + 1, z, mod_pocketDim.blockRift.blockID, 0, 3); + sendChat(sender, "Created a rift to \"" + result.schematicName() + "\" dungeon (Dimension ID = " + link.destination().getDimension() + ")."); + } + else + { + // Dungeon generation failed somehow. Notify the user and remove the useless link. + dimension.deleteLink(link); + sendChat(sender, "Dungeon generation failed unexpectedly!"); + } } else { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java index 67b1b116..e41a4674 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java @@ -3,6 +3,7 @@ package StevenDimDoors.mod_pocketDim.config; import java.io.File; import net.minecraftforge.common.Configuration; +import StevenDimDoors.mod_pocketDim.blocks.BlockRift; import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator; import StevenDimDoors.mod_pocketDim.world.fortresses.DDStructureNetherBridgeStart; import StevenDimDoors.mod_pocketDim.world.gateways.GatewayGenerator; @@ -107,6 +108,8 @@ public class DDProperties public final int GatewayGenerationChance; public final int FortressGatewayGenerationChance; public final int MonolithSpawningChance; + public final int WorldThreadDropChance; + public final int LimboEntryRange; public final int LimboReturnRange; public final int WorldThreadRequirementLevel; public final String CustomSchematicDirectory; @@ -166,8 +169,10 @@ public class DDProperties "Sets whether players keep their inventories upon dying and respawning in Limbo").getBoolean(true); HardcoreLimboEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Hardcore Limbo", false, "Sets whether players that die in Limbo will respawn there").getBoolean(false); + LimboEntryRange = config.get(Configuration.CATEGORY_GENERAL, "Limbo Entry Range", 500, + "Sets the farthest distance that players may be moved at random when sent to Limbo. Must be greater than or equal to 0.").getInt(); LimboReturnRange = config.get(Configuration.CATEGORY_GENERAL, "Limbo Return Range", 500, - "Sets the farthest distance that Limbo can send you upon returning to the Overworld").getInt(); + "Sets the farthest distance that players may be moved at random when sent from Limbo to the Overworld. Must be greater than or equal to 0.").getInt(); DoorRenderingEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Door Rendering", true).getBoolean(true); TNFREAKINGT_Enabled = config.get(Configuration.CATEGORY_GENERAL, "EXPLOSIONS!!???!!!?!?!!", false).getBoolean(false); @@ -206,8 +211,8 @@ public class DDProperties "Perma Fabric Block ID", 220, "Blocks used for enclosing pocket dimensions").getInt(); LimboDimensionID = config.get(CATEGORY_DIMENSION, "Limbo Dimension ID", -23).getInt(); - PocketProviderID = config.get(CATEGORY_PROVIDER, "Pocket Provider ID", 24).getInt(); - LimboProviderID = config.get(CATEGORY_PROVIDER, "Limbo Provider ID", 13).getInt(); + PocketProviderID = config.get(CATEGORY_PROVIDER, "Pocket Provider ID", 124).getInt(); + LimboProviderID = config.get(CATEGORY_PROVIDER, "Limbo Provider ID", 113).getInt(); MonolithTeleportationEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Monolith Teleportation", true, "Sets whether Monoliths can teleport players").getBoolean(true); @@ -227,9 +232,13 @@ public class DDProperties FortressGatewayGenerationChance = config.get(Configuration.CATEGORY_GENERAL, "Fortress Gateway Generation Chance", 33, "Sets the chance (out of " + DDStructureNetherBridgeStart.MAX_GATEWAY_GENERATION_CHANCE + ") that a Rift Gateway will " + "generate as part of a Nether Fortress. The default chance is 33.").getInt(); + + WorldThreadDropChance = config.get(Configuration.CATEGORY_GENERAL, "World Thread Drop Chance", 50, + "Sets the chance (out of " + BlockRift.MAX_WORLD_THREAD_DROP_CHANCE + ") that a rift will " + + "drop World Thread when it destroys a block. The default chance is 50.").getInt(); - LimboBiomeID = config.get(CATEGORY_BIOME, "Limbo Biome ID", 251).getInt(); - PocketBiomeID = config.get(CATEGORY_BIOME, "Pocket Biome ID", 250).getInt(); + LimboBiomeID = config.get(CATEGORY_BIOME, "Limbo Biome ID", 148).getInt(); + PocketBiomeID = config.get(CATEGORY_BIOME, "Pocket Biome ID", 149).getInt(); config.save(); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index bdb7fd71..0c95b061 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -9,8 +9,8 @@ import net.minecraft.entity.EntityList; import net.minecraft.entity.item.EntityMinecart; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemDoor; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.packet.Packet250CustomPayload; import net.minecraft.network.packet.Packet41EntityEffect; import net.minecraft.network.packet.Packet43Experience; import net.minecraft.network.packet.Packet9Respawn; @@ -20,14 +20,11 @@ import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.DimensionManager; -import net.minecraftforge.common.network.ForgePacket; -import net.minecraftforge.common.network.packet.DimensionRegisterPacket; import StevenDimDoors.mod_pocketDim.Point3D; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper; -import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor; import StevenDimDoors.mod_pocketDim.schematic.BlockRotator; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor; @@ -49,6 +46,7 @@ public class DDTeleporter 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; + private static final String SPIRIT_WORLD_NAME = "Spirit World"; public static int cooldown = 0; @@ -605,7 +603,7 @@ public class DDTeleporter } } - BaseItemDoor.placeDoorBlock(destWorld, link.destination().getX(), link.destination().getY()-1, link.destination().getZ(),link.getDestinationOrientation(), door); + ItemDoor.placeDoorBlock(destWorld, link.destination().getX(), link.destination().getY()-1, link.destination().getZ(),link.getDestinationOrientation(), door); TileEntity doorDestTE = ((BaseDimDoor)door).initDoorTE(destWorld, link.destination().getX(), link.destination().getY(), link.destination().getZ()); @@ -647,9 +645,7 @@ public class DDTeleporter for (int attempts = 0; attempts < 10; attempts++) { NewDimData selection = roots.get( random.nextInt(roots.size()) ); - if (selection.id() != END_DIMENSION_ID && - selection.id() != properties.LimboDimensionID && - selection != current.root()) + if (selection != current.root() && isValidForDungeonExit(selection, properties)) { return generateSafeExit(selection, link, properties); } @@ -660,6 +656,19 @@ public class DDTeleporter return generateSafeExit(current.root(), link, properties); } + private static boolean isValidForDungeonExit(NewDimData destination, DDProperties properties) + { + // Prevent exits to The End and Limbo + if (destination.id() == END_DIMENSION_ID || destination.id() == properties.LimboDimensionID) + { + return false; + } + // Prevent exits to Witchery's Spirit World; we need to load the dimension to retrieve its name. + // This is okay because the dimension would have to be loaded subsequently by generateSafeExit(). + World world = PocketManager.loadDimension(destination.id()); + return (world != null && !SPIRIT_WORLD_NAME.equals(world.provider.getDimensionName())); + } + private static boolean generateSafeExit(NewDimData destinationDim, DimLink link, DDProperties properties) { // A safe exit attempts to place a Warp Door in a dimension with diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java index 38848ad3..23bd064a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java @@ -184,11 +184,11 @@ public class DungeonSchematic extends Schematic { { if (notifyClients) { - copyToWorld(world, pocketCenter, targetOrientation, entryLink, random, properties, new WorldBlockSetter(false, true)); + copyToWorld(world, pocketCenter, targetOrientation, entryLink, random, properties, new WorldBlockSetter(false, true, false)); } else { - copyToWorld(world, pocketCenter, targetOrientation, entryLink, random, properties, new ChunkBlockSetter()); + copyToWorld(world, pocketCenter, targetOrientation, entryLink, random, properties, new ChunkBlockSetter(false)); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java index f1242259..e44a58bf 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java @@ -57,16 +57,6 @@ public class FillContainersOperation extends WorldOperation } } } - - // Fill dispensers - if (tileEntity instanceof TileEntityDispenser) - { - TileEntityDispenser dispenser = (TileEntityDispenser) tileEntity; - if (isInventoryEmpty(dispenser)) - { - dispenser.addItem(new ItemStack(Item.arrow, 64)); - } - } } return true; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java index af997fa5..4a37e85c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java @@ -21,6 +21,7 @@ public class DungeonPack //FIXME: Do not release this code as an update without dealing with disowned types! private static final int MAX_HISTORY_LENGTH = 30; + private static final int MAX_SUBTREE_LIST_SIZE = 30; private final String name; private final HashMap nameToTypeMapping; @@ -122,7 +123,7 @@ public class DungeonPack } } - public DungeonData getNextDungeon(NewDimData dimension, Random random) + public DungeonData getNextDungeon(NewDimData parent, Random random) { if (allDungeons.isEmpty()) { @@ -135,16 +136,36 @@ public class DungeonPack //for dungeon packs that can extend arbitrarily deep. We should probably set a reasonable limit anyway. int maxSearchLength = config.allowDuplicatesInChain() ? maxRuleLength : MAX_HISTORY_LENGTH; - ArrayList history = DungeonHelper.getDungeonChainHistory(dimension, this, maxSearchLength); - return getNextDungeon(history, random); + ArrayList history = DungeonHelper.getDungeonChainHistory(parent, this, maxSearchLength); + + ArrayList subtreeHistory = null; + if (config.getDuplicateSearchLevels() > 0) + { + // Search over (DuplicateSearchLevels - 1); zero means don't search at all, + // one means search only up to the level of the immediate parent, and so on. + // Since we start with the parent, we need to drop the max levels by one. + NewDimData ancestor = DungeonHelper.getAncestor(parent, this, config.getDuplicateSearchLevels() - 1); + if (ancestor != null) + { + subtreeHistory = DungeonHelper.listDungeonsInTree(ancestor, this, MAX_SUBTREE_LIST_SIZE); + } + } + if (subtreeHistory == null) + { + subtreeHistory = new ArrayList(); + } + subtreeHistory = new ArrayList(); + + return getNextDungeon(history, subtreeHistory, random); } - private DungeonData getNextDungeon(ArrayList history, Random random) + private DungeonData getNextDungeon(ArrayList history, ArrayList subtreeHistory, Random random) { //Extract the dungeon types that have been used from history and convert them into an array of IDs int index; int[] typeHistory = new int[history.size()]; HashSet excludedDungeons = null; + boolean doExclude = !config.allowDuplicatesInChain() || !subtreeHistory.isEmpty(); for (index = 0; index < typeHistory.length; index++) { typeHistory[index] = history.get(index).dungeonType().ID; @@ -163,9 +184,19 @@ public class DungeonPack if (nextType != null) { //Initialize the set of excluded dungeons if needed - if (excludedDungeons == null && !config.allowDuplicatesInChain()) + if (excludedDungeons == null && doExclude) { - excludedDungeons = new HashSet(history); + if (config.allowDuplicatesInChain()) + { + excludedDungeons = new HashSet(subtreeHistory); + excludedDungeons.addAll(subtreeHistory); + } + else + { + excludedDungeons = new HashSet(2 * (history.size() + subtreeHistory.size())); + excludedDungeons.addAll(history); + excludedDungeons.addAll(subtreeHistory); + } } //List which dungeons are allowed diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfig.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfig.java index 00745450..e5eaa54b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfig.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfig.java @@ -11,6 +11,7 @@ public class DungeonPackConfig private boolean allowPackChangeOut; private boolean distortDoorCoordinates; private int packWeight; + private int duplicateSearchLevels; private ArrayList rules; public DungeonPackConfig() { } @@ -25,6 +26,7 @@ public class DungeonPackConfig this.allowPackChangeOut = source.allowPackChangeOut; this.distortDoorCoordinates = source.distortDoorCoordinates; this.packWeight = source.packWeight; + this.duplicateSearchLevels = source.duplicateSearchLevels; this.rules = (source.rules != null) ? (ArrayList) source.rules.clone() : null; } @@ -114,6 +116,16 @@ public class DungeonPackConfig this.packWeight = packWeight; } + public int getDuplicateSearchLevels() + { + return duplicateSearchLevels; + } + + public void setDuplicateSearchLevels(int duplicateSearchLevels) + { + this.duplicateSearchLevels = duplicateSearchLevels; + } + public boolean doDistortDoorCoordinates() { return distortDoorCoordinates; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java index e24ecc69..0f8b05c0 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java @@ -35,6 +35,8 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor= MIN_DUPLICATE_SEARCH_LEVELS && levels <= MAX_DUPLICATE_SEARCH_LEVELS) + { + config.setDuplicateSearchLevels(levels); + } + else + { + valid = false; + } + } else { valid = false; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 545168d7..2c9775e3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -4,10 +4,10 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileFilter; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -32,7 +32,6 @@ import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPackConfig; import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPackConfigReader; import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonType; import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor; -import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException; import StevenDimDoors.mod_pocketDim.util.FileFilters; import StevenDimDoors.mod_pocketDim.util.WeightedContainer; @@ -48,10 +47,7 @@ public class DungeonHelper private static final String DEFAULT_ERROR_SCHEMATIC_PATH = "/schematics/core/somethingBroke.schematic"; private static final String DUNGEON_CREATION_GUIDE_SOURCE_PATH = "/mods/DimDoors/text/How_to_add_dungeons.txt"; - private static final String RUINS_PACK_PATH = "/schematics/ruins"; - private static final String BUNDLED_RUINS_LIST_PATH = "/schematics/ruins.txt"; - private static final String NETHER_PACK_PATH = "/schematics/nether"; - private static final String BUNDLED_NETHER_LIST_PATH = "/schematics/nether.txt"; + private static final String BUNDLED_PACK_BASE_PATH = "/schematics/"; private static final String STANDARD_CONFIG_FILE_NAME = "rules.txt"; private static final int NETHER_DIMENSION_ID = -1; @@ -158,7 +154,7 @@ public class DungeonHelper return null; } - private void registerDungeonPack(String directory, Iterable schematics, boolean isInternal, boolean verbose, DungeonPackConfigReader reader) + private DungeonPack registerDungeonPack(String directory, Iterable schematics, boolean isInternal, boolean verbose, DungeonPackConfigReader reader) { //First determine the pack's name and validate it File packDirectory = new File(directory); @@ -187,7 +183,7 @@ public class DungeonHelper if (config == null) { System.err.println("Could not load config file: " + configPath); - return; + return null; } //Register the pack @@ -208,6 +204,7 @@ public class DungeonHelper { registerDungeon(schematicPath, pack, isInternal, verbose); } + return pack; } public List getRegisteredDungeons() @@ -231,10 +228,14 @@ public class DungeonHelper return dungeonPackMapping.get(name.toUpperCase()); } - private DungeonPack getDimDungeonPack(NewDimData data) + private DungeonPack getDimDungeonPack(NewDimData dimension) { + // TODO: Drop support for dim-based packs and switch to embedding the pack + // in the link data itself. That would solve the dungeon pre-generation issue. + // Gateways should dictate which packs are being used, not the dimensions. + DungeonPack pack; - DungeonData dungeon = data.dungeon(); + DungeonData dungeon = dimension.dungeon(); if (dungeon != null) { pack = dungeon.dungeonType().Owner; @@ -247,7 +248,7 @@ public class DungeonHelper } else { - if (data.id() == NETHER_DIMENSION_ID) + if (dimension.id() == NETHER_DIMENSION_ID) { pack = NetherPack; } @@ -433,32 +434,30 @@ public class DungeonHelper defaultError = new DungeonData(DEFAULT_ERROR_SCHEMATIC_PATH, true, DungeonType.UNKNOWN_TYPE, true, DEFAULT_DUNGEON_WEIGHT); //Open the list of dungeons packaged with our mod and register their schematics - registerBundledPack(BUNDLED_RUINS_LIST_PATH, RUINS_PACK_PATH, "Ruins", reader); - RuinsPack = getDungeonPack("Ruins"); - - registerBundledPack(BUNDLED_NETHER_LIST_PATH, NETHER_PACK_PATH, "Nether", reader); - NetherPack = getDungeonPack("Nether"); + RuinsPack = registerBundledPack("Ruins", reader); + NetherPack = registerBundledPack("Nether", reader); System.out.println("Finished registering bundled dungeon packs"); } - private void registerBundledPack(String listPath, String packPath, String name, DungeonPackConfigReader reader) + private DungeonPack registerBundledPack(String name, DungeonPackConfigReader reader) { System.out.println("Registering bundled dungeon pack: " + name); + String packPath = BUNDLED_PACK_BASE_PATH + name.toLowerCase(); + String listPath = packPath + ".txt"; InputStream listStream = this.getClass().getResourceAsStream(listPath); - // chance of leak? + if (listStream == null) { - System.err.println("Unable to open list of bundled dungeon schematics for " + name); - return; + throw new IllegalStateException("Failed to open the list of bundled dungeon schematics for " + name); } + ArrayList schematics = new ArrayList(); try { - //Read the list of schematics that come with a bundled pack + // Read the list of schematics that come with a bundled pack BufferedReader listReader = new BufferedReader(new InputStreamReader(listStream)); - ArrayList schematics = new ArrayList(); String schematicPath = listReader.readLine(); while (schematicPath != null) { @@ -470,15 +469,19 @@ public class DungeonHelper schematicPath = listReader.readLine(); } listReader.close(); - - //Register the pack - registerDungeonPack(packPath, schematics, true, false, reader); } - catch (Exception e) + catch (IOException e) { - System.err.println("An exception occurred while reading the list of bundled dungeon schematics for " + name); - e.printStackTrace(); + throw new RuntimeException("An unexpected error occured while trying to read the list of schematics for the " + name + " bundled dungeon pack. This would inevitably cause Dimensional Doors to crash during runtime.", e); } + + // Register the pack + DungeonPack pack = registerDungeonPack(packPath, schematics, true, false, reader); + if (pack == null) + { + throw new RuntimeException("Failed to load the " + name + " bundled dungeon pack. This would inevitably cause Dimensional Doors to crash during runtime."); + } + return pack; } public boolean exportDungeon(World world, int centerX, int centerY, int centerZ, String exportPath) @@ -500,9 +503,9 @@ public class DungeonHelper } } - public DungeonData selectDungeon(NewDimData dimension, Random random) + public DungeonData selectNextDungeon(NewDimData parent, Random random) { - DungeonPack pack = getDimDungeonPack(dimension.parent()); + DungeonPack pack = getDimDungeonPack(parent); DungeonData selection; DungeonPackConfig config; DungeonPack selectedPack; @@ -512,30 +515,30 @@ public class DungeonHelper config = pack.getConfig(); selectedPack = pack; - //Are we allowed to switch to another dungeon pack? + // Are we allowed to switch to another dungeon pack? if (config.allowPackChangeOut()) { - //Calculate the chance of switching to a different pack type + // Calculate the chance of switching to a different pack type int packSwitchChance; - if (dimension.depth() == 1) + if (parent.isPocketDimension()) { - packSwitchChance = START_PACK_SWITCH_CHANCE; + packSwitchChance = MIN_PACK_SWITCH_CHANCE + parent.packDepth() * PACK_SWITCH_CHANCE_PER_LEVEL; } else { - packSwitchChance = MIN_PACK_SWITCH_CHANCE + dimension.parent().packDepth() * PACK_SWITCH_CHANCE_PER_LEVEL; + packSwitchChance = START_PACK_SWITCH_CHANCE; } - //Decide randomly whether to switch packs or not + // Decide randomly whether to switch packs or not if (random.nextInt(MAX_PACK_SWITCH_CHANCE) < packSwitchChance) { - //Find another pack + // Find another pack selectedPack = getRandomDungeonPack(pack, random); } } //Pick the next dungeon - selection = selectedPack.getNextDungeon(dimension, random); + selection = selectedPack.getNextDungeon(parent, random); } catch (Exception e) { @@ -609,59 +612,95 @@ public class DungeonHelper return names; } - public static ArrayList getDungeonChainHistory(NewDimData dimension, DungeonPack pack, int maxSize) + /** + * Lists all of the dungeons found by iterating through a dimension's ancestors. The search stops when a non-dungeon dimension is found or when the pack of a dungeon differs from the specified pack. + * @param start - the first dimension to include in the history + * @param pack - the pack to which any dungeons must belong in order to be listed + * @param maxSize - the maximum number of dungeons that can be listed + * @return a list of dungeons used in a given chain + */ + public static ArrayList getDungeonChainHistory(NewDimData start, DungeonPack pack, int maxSize) { - if (dimension == null) + if (start == null) { throw new IllegalArgumentException("dimension cannot be null."); } - if(dimension.parent()==null) - { - return new ArrayList(); - } int count = 0; - NewDimData tail = dimension.parent(); - DungeonData dungeon = tail.dungeon(); + NewDimData current = start; + DungeonData dungeon = current.dungeon(); ArrayList history = new ArrayList(); while (count < maxSize && dungeon != null && dungeon.dungeonType().Owner == pack) { history.add(dungeon); - tail = tail.parent(); - dungeon = tail.dungeon(); + current = current.parent(); + dungeon = current.dungeon(); count++; } return history; } - public static ArrayList getFlatDungeonTree(NewDimData dimension, int maxSize) + /** + * Performs a breadth-first listing of all dungeons rooted at a specified dimension. Only dungeons from the specified pack will be included. + * @param root - the pocket dimension that serves as the root for the dungeon tree + * @param pack - the pack to which any dungeons must belong in order to be listed + * @param maxSize - the maximum number of dungeons that can be listed + * @return a list of the dungeons used in a given dungeon tree + */ + public static ArrayList listDungeonsInTree(NewDimData root, DungeonPack pack, int maxSize) { - NewDimData root = dimension; + int count = 0; + NewDimData current; + DungeonData dungeon; ArrayList dungeons = new ArrayList(); - Queue pendingDimensions = new LinkedList(); - - if (root.dungeon() == null) - { - return dungeons; - } + Queue pendingDimensions = new LinkedList(); pendingDimensions.add(root); + // Perform a breadth-first search through the dungeon graph while (dungeons.size() < maxSize && !pendingDimensions.isEmpty()) { - NewDimData current = pendingDimensions.remove(); - for (NewDimData child : current.children()) + current = pendingDimensions.remove(); + dungeon = current.dungeon(); + // Check that this is a dungeon, and if so, that it belongs to the pack that we want + if (dungeon != null && dungeon.dungeonType().Owner == pack) { - if (child.dungeon() != null) + dungeons.add(dungeon); + // Add all child dungeons for checking later + for (NewDimData child : current.children()) { - dungeons.add(child.dungeon()); pendingDimensions.add(child); } - if (dungeons.size() == maxSize) - { - break; - } } } return dungeons; } + + /** + * Gets the highest ancestor of a dimension with a dungeon that belongs to the specified pack. + * @param dimension - the first dimension to include in the search + * @param pack - the pack to which the ancestors must belong + * @param maxLevels - the maximum number of ancestors to check + * @return the highest ancestor that belongs to the specified pack within the specified levels, or null if none exists + */ + public static NewDimData getAncestor(NewDimData dimension, DungeonPack pack, int maxLevels) + { + // Find the ancestor of a dimension located a specified number of levels up. + NewDimData parent = dimension; + NewDimData current = null; + + // We solve this inductively. We begin with null as the first valid ancestor, + // like a kind of virtual child dimension. Then "current" references the + // highest valid ancestor found so far and "parent" references its parent + for (int levels = 0; levels <= maxLevels; levels++) + { + if (parent == null || parent.dungeon() == null || + parent.dungeon().dungeonType().Owner != pack) + { + break; + } + current = parent; + parent = parent.parent(); + } + return current; + } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java index c17da83d..4d1cf840 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java @@ -119,8 +119,8 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature else { par3List.add("First click stores a location,"); - par3List.add("second click creates two rifts"); - par3List.add("that link the locations together."); + par3List.add("other clicks create rifts linking"); + par3List.add("the first and last locations together."); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index a5f2e8a7..09bb6d6f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -124,7 +124,7 @@ public class mod_pocketDim public static Item itemWorldThread; public static Item itemRiftBlade; - public static Item itemDimensionalDoor; + public static ItemDimensionalDoor itemDimensionalDoor; public static Item itemWarpDoor; public static Item itemRiftRemover; public static Item itemRiftSignature; @@ -203,7 +203,7 @@ public class mod_pocketDim itemGoldenDimensionalDoor = (new ItemGoldDimDoor(properties.GoldenDimensionalDoorItemID, Material.iron)).setUnlocalizedName("itemGoldDimDoor"); itemGoldenDoor = (new ItemGoldDoor(properties.GoldenDoorID, Material.wood)).setUnlocalizedName("itemGoldDoor"); - itemDimensionalDoor = (new ItemDimensionalDoor(properties.DimensionalDoorItemID, Material.iron)).setUnlocalizedName("itemDimDoor"); + itemDimensionalDoor = (ItemDimensionalDoor) (new ItemDimensionalDoor(properties.DimensionalDoorItemID, Material.iron)).setUnlocalizedName("itemDimDoor"); itemWarpDoor = (new ItemWarpDoor(properties.WarpDoorItemID, Material.wood)).setUnlocalizedName("itemDimDoorWarp"); itemRiftSignature = (new ItemRiftSignature(properties.RiftSignatureItemID)).setUnlocalizedName("itemLinkSignature"); itemRiftRemover = (new itemRiftRemover(properties.RiftRemoverItemID, Material.wood)).setUnlocalizedName("itemRiftRemover"); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/ChunkBlockSetter.java b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/ChunkBlockSetter.java index e7203fb4..b00195c8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/ChunkBlockSetter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/ChunkBlockSetter.java @@ -7,11 +7,16 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage; public class ChunkBlockSetter implements IBlockSetter { - public ChunkBlockSetter() { } + private boolean ignoreAir; + + public ChunkBlockSetter(boolean ignoreAir) + { + this.ignoreAir = ignoreAir; + } public void setBlock(World world, int x, int y, int z, int blockID, int metadata) { - if (blockID != 0 && Block.blocksList[blockID] == null) + if ((blockID == 0 && ignoreAir) || (blockID != 0 && Block.blocksList[blockID] == null)) { return; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/Schematic.java b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/Schematic.java index 8bf7dbbc..dbb912fc 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/Schematic.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/Schematic.java @@ -362,15 +362,15 @@ public class Schematic { return filter.apply(this, this.blocks, this.metadata); } - public void copyToWorld(World world, int x, int y, int z, boolean notifyClients) + public void copyToWorld(World world, int x, int y, int z, boolean notifyClients, boolean ignoreAir) { if (notifyClients) { - copyToWorld(world, x, y, z, new WorldBlockSetter(false, true)); + copyToWorld(world, x, y, z, new WorldBlockSetter(false, true, ignoreAir)); } else { - copyToWorld(world, x, y, z, new ChunkBlockSetter()); + copyToWorld(world, x, y, z, new ChunkBlockSetter(ignoreAir)); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/WorldBlockSetter.java b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/WorldBlockSetter.java index 3ac4563e..2ff9e089 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/WorldBlockSetter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/WorldBlockSetter.java @@ -11,16 +11,21 @@ public class WorldBlockSetter implements IBlockSetter public final int NOTIFY_CLIENT_FLAG = 2; private int flags; + private boolean ignoreAir; - public WorldBlockSetter(boolean doBlockUpdates, boolean notifyClients) + public WorldBlockSetter(boolean doBlockUpdates, boolean notifyClients, boolean ignoreAir) { - flags = 0; - flags += doBlockUpdates ? BLOCK_UPDATES_FLAG : 0; - flags += notifyClients ? NOTIFY_CLIENT_FLAG : 0; + this.flags = 0; + this.flags += doBlockUpdates ? BLOCK_UPDATES_FLAG : 0; + this.flags += notifyClients ? NOTIFY_CLIENT_FLAG : 0; + this.ignoreAir = ignoreAir; } public void setBlock(World world, int x, int y, int z, int blockID, int metadata) { - world.setBlock(x, y, z, blockID, metadata, flags); + if (!ignoreAir || blockID != 0) + { + world.setBlock(x, y, z, blockID, metadata, flags); + } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java index 465e57b2..2f4522ae 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java @@ -37,24 +37,36 @@ public class CustomLimboPopulator implements IRegularTickReceiver { @Override public void notifyTick() { - //Check if any new spawning requests have come in + World limboWorld = null; + + // Check if any new spawning requests have come in if (!locations.isEmpty()) { - //Check if mob spawning is allowed + // Check if mob spawning is allowed if (isMobSpawningAllowed()) { - //Loop over the locations and call the appropriate function depending - //on whether the request is for Limbo or for a pocket dimension. + // Loop over the locations and call the appropriate function depending + // on whether the request is for Limbo or for a pocket dimension. for (ChunkLocation location : locations) { if (location.DimensionID == properties.LimboDimensionID) { - //Limbo chunk - placeMonolithsInLimbo(location.DimensionID, location.ChunkX, location.ChunkZ); + // Limbo chunk - World world = DimensionManager.getWorld(location.DimensionID); + // SenseiKiwi: Check if we haven't loaded Limbo for another request in this request + // cycle. If so, try to load Limbo up. This solves a strange issue with ChickenChunks + // where CC somehow forces chunks to generate in Limbo if LimboProvider.canRespawnHere() + // is true, yet when execution reaches this point, Limbo isn't loaded anymore! My theory + // is that CC force-loads a chunk for some reason, but since there are no players around, + // Limbo immediately unloads after standard world gen runs, and before this code can run. - mod_pocketDim.instance.gatewayGenerator.generate(world.rand, location.ChunkX, location.ChunkZ,world, world.getChunkProvider(), world.getChunkProvider()); + if (limboWorld == null) + { + limboWorld = PocketManager.loadDimension(properties.LimboDimensionID); + } + placeMonolithsInLimbo(limboWorld, location.ChunkX, location.ChunkZ); + mod_pocketDim.instance.gatewayGenerator.generate(limboWorld.rand, location.ChunkX, location.ChunkZ, + limboWorld, limboWorld.getChunkProvider(), limboWorld.getChunkProvider()); } else { @@ -145,15 +157,8 @@ public class CustomLimboPopulator implements IRegularTickReceiver { while (sanity < 5 && !didSpawn); } - private void placeMonolithsInLimbo(int dimensionID, int chunkX, int chunkZ) + private void placeMonolithsInLimbo(World limbo, int chunkX, int chunkZ) { - World limbo = DimensionManager.getWorld(dimensionID); - - if (limbo == null) - { - return; - } - //The following initialization code is based on code from ChunkProviderGenerate. //It makes our generation depend on the world seed. Random random = new Random(limbo.getSeed() ^ 0xB5130C4ACC71A822L); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index ae1f7cc9..36df4dcf 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -195,8 +195,7 @@ public class MobMonolith extends EntityFlying implements IMob } else if (!this.worldObj.isRemote && properties.MonolithTeleportationEnabled && !entityPlayer.capabilities.isCreativeMode) { - ChunkCoordinates coords = LimboProvider.getLimboSkySpawn(entityPlayer.worldObj.rand); - Point4D destination = new Point4D((int) (coords.posX+entityPlayer.posX), coords.posY, (int) (coords.posZ+entityPlayer.posZ ), mod_pocketDim.properties.LimboDimensionID); + Point4D destination = LimboProvider.getLimboSkySpawn(entityPlayer, properties); DDTeleporter.teleportEntity(entityPlayer, destination, false); this.aggro = 0; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java index 3be95209..9e220535 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java @@ -3,8 +3,10 @@ package StevenDimDoors.mod_pocketDim.world; import java.util.Random; import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import net.minecraft.world.WorldProvider; import net.minecraft.world.biome.BiomeGenBase; @@ -15,6 +17,7 @@ import StevenDimDoors.mod_pocketDim.CloudRenderBlank; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator; +import StevenDimDoors.mod_pocketDim.util.Point4D; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -59,7 +62,7 @@ public class LimboProvider extends WorldProvider @Override public boolean canRespawnHere() { - return properties.HardcoreLimboEnabled && properties.LimboEnabled; + return properties.HardcoreLimboEnabled; } @Override @@ -174,26 +177,18 @@ public class LimboProvider extends WorldProvider return false; } - public static ChunkCoordinates getLimboSkySpawn(Random rand) + public static Point4D getLimboSkySpawn(EntityPlayer player, DDProperties properties) { - ChunkCoordinates var5 = new ChunkCoordinates(0,0,0); - - - int spawnFuzz = 1000; - int spawnFuzzHalf = spawnFuzz / 2; - - { - var5.posX += rand.nextInt(spawnFuzz) - spawnFuzzHalf; - var5.posZ += rand.nextInt(spawnFuzz) - spawnFuzzHalf; - var5.posY = 700; - } - - return var5; + int x = (int) (player.posX) + MathHelper.getRandomIntegerInRange(player.worldObj.rand, -properties.LimboEntryRange, properties.LimboEntryRange); + int z = (int) (player.posZ) + MathHelper.getRandomIntegerInRange(player.worldObj.rand, -properties.LimboEntryRange, properties.LimboEntryRange); + return new Point4D(x, 700, z, properties.LimboDimensionID); } @Override public ChunkCoordinates getRandomizedSpawnPoint() { - return getLimboSkySpawn(this.worldObj.rand); + int x = MathHelper.getRandomIntegerInRange(this.worldObj.rand, -500, 500); + int z = MathHelper.getRandomIntegerInRange(this.worldObj.rand, -500, 500); + return new ChunkCoordinates(x, 700, z); } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index c384ec48..f26939b6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -104,8 +104,13 @@ public class PocketBuilder return false; } + DungeonSchematic schematic = loadAndValidateDungeon(dimension.dungeon(), properties); + if (schematic == null) + { + return false; + } Point3D destination = new Point3D(incomingLink.destination()); - loadAndValidateDungeon(dimension.dungeon(), properties).copyToWorld(world, destination, originLink.orientation(), incomingLink, random, properties, false); + schematic.copyToWorld(world, destination, originLink.orientation(), incomingLink, random, properties, false); dimension.setFilled(true); return true; } @@ -145,7 +150,7 @@ public class PocketBuilder return true; } - public static boolean generateSelectedDungeonPocket(DimLink link, DDProperties properties, DungeonData data) + public static boolean generateSelectedDungeonPocket(DimLink link, DDProperties properties, DungeonData dungeon) { if (link == null) { @@ -155,13 +160,24 @@ public class PocketBuilder { throw new IllegalArgumentException("properties cannot be null."); } - if (link.hasDestination()) { throw new IllegalArgumentException("link cannot have a destination assigned already."); } + if (dungeon == null) + { + throw new IllegalArgumentException("dungeon cannot be null."); + } - //Register a new dimension + // Try to load up the schematic + DungeonSchematic schematic = null; + schematic = loadAndValidateDungeon(dungeon, properties); + if (schematic == null) + { + return false; + } + + // Register a new dimension NewDimData parent = PocketManager.getDimensionData(link.source().getDimension()); NewDimData dimension = PocketManager.registerPocket(parent, true); @@ -174,19 +190,7 @@ public class PocketBuilder return false; } - DungeonData dungeon = null; - DungeonSchematic schematic = null; - - dungeon = data; - if (data == null) - { - System.err.println("Could not select a dungeon for generation!"); - return false; - } - schematic = loadAndValidateDungeon(dungeon, properties); - return PocketBuilder.buildDungeonPocket(dungeon, dimension, link, schematic, world, properties); - } @@ -206,10 +210,18 @@ public class PocketBuilder throw new IllegalArgumentException("link cannot have a destination assigned already."); } - + //Choose a dungeon to generate + NewDimData parent = PocketManager.getDimensionData(link.source().getDimension()); + Pair pair = selectNextDungeon(parent, 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(); //Register a new dimension - NewDimData parent = PocketManager.getDimensionData(link.source().getDimension()); NewDimData dimension = PocketManager.registerPocket(parent, true); //Load a world @@ -220,17 +232,7 @@ public class PocketBuilder System.err.println("Could not initialize dimension for a dungeon!"); return false; } - - //Choose a dungeon to generate - 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(); - + return buildDungeonPocket(dungeon, dimension, link, schematic, world, properties); } @@ -251,18 +253,12 @@ public class PocketBuilder return linkDestination; } - private static Pair selectDungeon(NewDimData dimension, Random random, DDProperties properties) + private static Pair selectNextDungeon(NewDimData parent, Random random, DDProperties properties) { - //We assume the dimension doesn't have a dungeon assigned - if (dimension.dungeon() != null) - { - throw new IllegalArgumentException("dimension cannot have a dungeon assigned already."); - } - DungeonData dungeon = null; DungeonSchematic schematic = null; - dungeon = DungeonHelper.instance().selectDungeon(dimension, random); + dungeon = DungeonHelper.instance().selectNextDungeon(parent, random); if (dungeon != null) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java index d8c149ef..8b05b399 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Random; import net.minecraft.block.Block; +import net.minecraft.item.ItemDoor; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; import net.minecraft.world.gen.structure.StructureBoundingBox; @@ -13,7 +14,6 @@ import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.LinkTypes; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; -import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; public class ComponentNetherGateway extends StructureComponent { @@ -159,7 +159,7 @@ public class ComponentNetherGateway extends StructureComponent { link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); } - BaseItemDoor.placeDoorBlock(world, x, y, z, orientation, mod_pocketDim.transientDoor); + ItemDoor.placeDoorBlock(world, x, y, z, orientation, mod_pocketDim.transientDoor); } for (x = 0; x <= 6; ++x) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseGateway.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseGateway.java index 92572b70..58567b04 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseGateway.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseGateway.java @@ -1,136 +1,41 @@ package StevenDimDoors.mod_pocketDim.world.gateways; -import java.util.ArrayList; -import java.util.Map; -import java.util.Random; -import java.util.TreeMap; -import java.util.Map.Entry; - -import StevenDimDoors.mod_pocketDim.Point3D; -import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.config.DDProperties; -import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; -import StevenDimDoors.mod_pocketDim.core.NewDimData; -import StevenDimDoors.mod_pocketDim.core.PocketManager; -import StevenDimDoors.mod_pocketDim.dungeon.DungeonData; -import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic; -import StevenDimDoors.mod_pocketDim.dungeon.ModBlockFilter; -import StevenDimDoors.mod_pocketDim.dungeon.SpecialBlockFinder; -import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; -import StevenDimDoors.mod_pocketDim.schematic.BlockRotator; -import StevenDimDoors.mod_pocketDim.schematic.CompoundFilter; -import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException; -import StevenDimDoors.mod_pocketDim.schematic.ReplacementFilter; -import StevenDimDoors.mod_pocketDim.schematic.Schematic; -import StevenDimDoors.mod_pocketDim.schematic.SchematicFilter; -import StevenDimDoors.mod_pocketDim.world.PocketBuilder; -import net.minecraft.block.Block; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; +import StevenDimDoors.mod_pocketDim.config.DDProperties; public abstract class BaseGateway { - DDProperties properties; + protected DDProperties properties; public BaseGateway(DDProperties properties) { - this.properties=properties; + this.properties = properties; } /** - * Generates the gateway centered on the given coords - * @param world - * @param x - * @param y - * @param z + * Generates the gateway centered on the given coordinates + * @param world - the world in which to generate the gateway + * @param x - the x-coordinate at which to center the gateway; usually where the door is placed + * @param y - the y-coordinate of the block on which the gateway may be built + * @param z - the z-coordinate at which to center the gateway; usually where the door is placed */ - public boolean generate(World world, int x, int y, int z) - { - int orientation = 0; - - if (this.getSchematicPath()!=null) - { - //Get the correct filters - GatewayBlockFilter filter = new GatewayBlockFilter(); - DungeonSchematic schematic = this.getSchematicToBuild(world, x, y, z); - - //apply filters - schematic.applyFilter(filter); - schematic.applyImportFilters(properties); - - Point3D doorLocation = filter.getEntranceDoorLocation(); - orientation = filter.getEntranceOrientation(); - - // I suspect that the location used below is wrong. Gateways should be placed vertically based on - // the Y position of the surface where they belong. I'm pretty sure including doorLocation.getY() - // messes up the calculation. ~SenseiKiwi - - //schematic.copyToWorld(world, x - doorLocation.getX(), y, z - doorLocation.getZ()); - schematic.copyToWorld(world, x - doorLocation.getX(), y + 1 - doorLocation.getY(), z - doorLocation.getZ(), true); - } - - this.generateRandomBits(world, x, y, z); - - DimLink link = PocketManager.getDimensionData(world).createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); - PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, this.getStartingDungeon(PocketManager.getDimensionData(world),world.rand)); - - return true; - } + public abstract boolean generate(World world, int x, int y, int z); /** - * Gets a .schematic to generate for this gateway - * @param world - * @param x - * @param y - * @param z - * @return + * Determines whether the specified biome is a valid biome in which to generate this gateway + * @param biome - the biome to be checked + * @return true true if the specified biome is a valid for generating this gateway, otherwise false */ - public DungeonSchematic getSchematicToBuild(World world, int x, int y, int z) + protected boolean isBiomeValid(BiomeGenBase biome) { - //TODO- refine selection criteria here, this is the default case - try + String biomeName = biome.biomeName.toLowerCase(); + String[] keywords = this.getBiomeKeywords(); + if (keywords != null) { - return DungeonSchematic.readFromResource(this.getSchematicPath()); - } - catch (Exception e) - { - e.printStackTrace(); - System.err.println("Could not load schematic for gateway"); - return null; - } - } - - /** - * returns a dungeon from the assigned pack to start with - * @return - */ - public DungeonData getStartingDungeon(NewDimData dimension, Random random) - { - return getStartingPack().getNextDungeon(dimension,random); - } - - /** - * determines if a given location is valid for the gateway to be generated, based on height, biome, and world. - * @param world - * @param x - * @param y - * @param z - * @param biome - * @return - */ - public boolean isLocationValid(World world, int x, int y, int z, BiomeGenBase biome) - { - return this.isBiomeValid(biome)&&areCoordsValid(world, x, y, z); - } - - public boolean isBiomeValid(BiomeGenBase biome) - { - if(this.getBiomeNames()!=null) - { - for(String biomeName : this.getBiomeNames()) + for (String keyword : keywords) { - if(biome.biomeName.contains(biomeName)) + if (biomeName.contains(keyword)) { return true; } @@ -141,43 +46,33 @@ public abstract class BaseGateway } /** - * Use this function to generate randomized bits of the structure. - * @param world - * @param x - * @param y - * @param z + * Determines whether the specified world and coordinates are a valid location for generating this gateway + * @param world - the world in which to generate the gateway + * @param x - the x-coordinate at which to center the gateway; usually where the door is placed + * @param y - the y-coordinate of the block on which the gateway may be built + * @param z - the z-coordinate at which to center the gateway; usually where the door is placed + * @return true if the location is valid, otherwise false */ - abstract void generateRandomBits(World world, int x, int y, int z); - - /** - * Decides if the given coords/world are valid - * @param world - * @param x - * @param y - * @param z - * @return - */ - public abstract boolean areCoordsValid(World world, int x, int y, int z); + public boolean isLocationValid(World world, int x, int y, int z) + { + return isBiomeValid(world.getBiomeGenForCoords(x, z)); + } /** - * @return the pack the dungeon initially generates into from this gateway. + * Gets the dungeon pack associated with this gateway + * @return the dungeon pack to use for this gateway */ - public abstract DungeonPack getStartingPack(); + /*protected DungeonPack getDungeonPack() + { + return DungeonHelper.instance().getDungeonPack("RUINS"); + }*/ /** - * Is by default a whitelist, but the isBiomeValid method - * can be overriden for specific gateways. For example, any biome containing 'forest' would be valid if we added 'forest', - * even from other mods. - * @return List of biome names that we check against. + * Gets the lowercase keywords to be used in checking whether a given biome is a valid location for this gateway + * @return an array of biome keywords to match against */ - public abstract String[] getBiomeNames(); - - /** - * @return List containing all the .schematics attached to this gateway. Selection is random by default - */ - public abstract String getSchematicPath(); - - //TODO not yet implemented - public abstract boolean isSurfaceGateway(); - + public String[] getBiomeKeywords() + { + return new String[] { "" }; + } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java new file mode 100644 index 00000000..6eaa0dab --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java @@ -0,0 +1,66 @@ +package StevenDimDoors.mod_pocketDim.world.gateways; + +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.PocketManager; +import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic; +import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException; + +public abstract class BaseSchematicGateway extends BaseGateway +{ + public BaseSchematicGateway(DDProperties properties) + { + super(properties); + } + + @Override + public boolean generate(World world, int x, int y, int z) + { + DungeonSchematic schematic; + + try + { + schematic = DungeonSchematic.readFromResource(this.getSchematicPath()); + } + catch (InvalidSchematicException e) + { + System.err.println("Could not load the schematic for a gateway. The following exception occurred:"); + e.printStackTrace(); + return false; + } + + // Apply filters - the order is important! + GatewayBlockFilter gatewayFilter = new GatewayBlockFilter(); + schematic.applyFilter(gatewayFilter); + schematic.applyImportFilters(properties); + + Point3D doorLocation = gatewayFilter.getEntranceDoorLocation(); + int orientation = gatewayFilter.getEntranceOrientation(); + + // Build the gateway into the world + schematic.copyToWorld(world, x - doorLocation.getX(), y, z - doorLocation.getZ(), true, true); + this.generateRandomBits(world, x, y, z); + + // Generate a dungeon link in the door + PocketManager.getDimensionData(world).createLink(x, y + doorLocation.getY(), z, LinkTypes.DUNGEON, orientation); + + return true; + } + + /** + * Generates randomized portions of the gateway structure (e.g. rubble, foliage) + * @param world - the world in which to generate the gateway + * @param x - the x-coordinate at which to center the gateway; usually where the door is placed + * @param y - the y-coordinate of the block on which the gateway may be built + * @param z - the z-coordinate at which to center the gateway; usually where the door is placed + */ + protected void generateRandomBits(World world, int x, int y, int z) { } + + /** + * Gets the path for the schematic file to be used for this gateway. Subsequent calls to this method may return other schematic paths. + * @return the path to the schematic file for this gateway + */ + protected abstract String getSchematicPath(); +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java index 9936150f..dfd855a3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java @@ -25,13 +25,14 @@ public class GatewayGenerator implements IWorldGenerator private static final int CLUSTER_GROWTH_CHANCE = 80; private static final int MAX_CLUSTER_GROWTH_CHANCE = 100; private static final int MIN_RIFT_Y = 4; - private static final int MAX_RIFT_Y = 250; + private static final int MAX_RIFT_Y = 240; private static final int CHUNK_LENGTH = 16; private static final int GATEWAY_RADIUS = 4; private static final int MAX_GATEWAY_GENERATION_ATTEMPTS = 10; private static final int OVERWORLD_DIMENSION_ID = 0; private static final int NETHER_DIMENSION_ID = -1; private static final int END_DIMENSION_ID = 1; + private static final String SPIRIT_WORLD_NAME = "Spirit World"; private ArrayList gateways; private BaseGateway defaultGateway; @@ -50,7 +51,6 @@ public class GatewayGenerator implements IWorldGenerator defaultGateway = new GatewayTwoPillars(properties); // Add gateways here - gateways.add(defaultGateway); gateways.add(new GatewaySandstonePillars(properties)); gateways.add(new GatewayLimbo(properties)); } @@ -59,12 +59,14 @@ public class GatewayGenerator implements IWorldGenerator public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider) { // Don't generate rifts or gateways if the current world is a pocket dimension or the world is remote. - // Also don't generate anything in the Nether or The End. + // Also don't generate anything in the Nether, The End, or in Witchery's Spirit World. + // We only match against Spirit World using hashing to speed up the process a little (hopefully). int dimensionID = world.provider.dimensionId; if (world.isRemote || (world.provider instanceof PocketProvider) || (dimensionID == END_DIMENSION_ID) - || (dimensionID == NETHER_DIMENSION_ID)) + || (dimensionID == NETHER_DIMENSION_ID) + || (world.provider.getDimensionName().hashCode() == SPIRIT_WORLD_NAME.hashCode())) { return; } @@ -135,26 +137,24 @@ public class GatewayGenerator implements IWorldGenerator valid = checkGatewayLocation(world, x, y, z); } - //Build the gateway if we found a valid location + // Build the gateway if we found a valid location if (valid) { - //TODO I feel like this is slow and should be optimized. We are linear time with total # of generation restrictions - //Create an array and copy valid gateways into it ArrayList validGateways = new ArrayList(); - for(BaseGateway gateway:gateways) + for (BaseGateway gateway : gateways) { - if(gateway.isLocationValid(world, x, y, z, world.getBiomeGenForCoords(x, z))) + if (gateway.isLocationValid(world, x, y, z)) { validGateways.add(gateway); } } - //Add default gateway if we where unable to find a suitable gateway - if(validGateways.isEmpty()) + // Add the default gateway if the rest were rejected + if (validGateways.isEmpty()) { - validGateways.add(this.defaultGateway); + validGateways.add(defaultGateway); } - //randomly select a gateway from the pool of viable gateways - validGateways.get(random.nextInt(validGateways.size())).generate(world, x, y, z); + // Randomly select a gateway from the pool of viable gateways + validGateways.get(random.nextInt(validGateways.size())).generate(world, x, y - 1, z); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java index 6dbf10b9..cb50437d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java @@ -1,69 +1,42 @@ package StevenDimDoors.mod_pocketDim.world.gateways; +import net.minecraft.item.ItemDoor; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; -import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; -import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; -import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; +import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.world.LimboProvider; public class GatewayLimbo extends BaseGateway { - - public GatewayLimbo(DDProperties properties) { + public GatewayLimbo(DDProperties properties) + { super(properties); - // TODO Auto-generated constructor stub } @Override - void generateRandomBits(World world, int x, int y, int z) + public boolean generate(World world, int x, int y, int z) { int blockID = mod_pocketDim.blockLimbo.blockID; - //Build the gateway out of Unraveled Fabric. Since nearly all the blocks in Limbo are of - //that type, there is no point replacing the ground. - world.setBlock(x, y + 2, z + 1, blockID, 0, 3); - world.setBlock(x, y + 2, z - 1, blockID, 0, 3); + // Build the gateway out of Unraveled Fabric. Since nearly all the blocks in Limbo are of + // that type, there is no point replacing the ground. + world.setBlock(x, y + 3, z + 1, blockID, 0, 3); + world.setBlock(x, y + 3, z - 1, blockID, 0, 3); - //Build the columns around the door + // Build the columns around the door + world.setBlock(x, y + 2, z - 1, blockID, 0, 3); + world.setBlock(x, y + 2, z + 1, blockID, 0, 3); world.setBlock(x, y + 1, z - 1, blockID, 0, 3); world.setBlock(x, y + 1, z + 1, blockID, 0, 3); - world.setBlock(x, y, z - 1, blockID, 0, 3); - world.setBlock(x, y, z + 1, blockID, 0, 3); - - BaseItemDoor.placeDoorBlock(world, x, y, z, 0, mod_pocketDim.transientDoor); - - } - - @Override - public DungeonPack getStartingPack() { - // TODO Auto-generated method stub - return DungeonHelper.instance().getDungeonPack("RUINS"); - } - - @Override - public String[] getBiomeNames() { - // TODO Auto-generated method stub - return null; - } - - @Override - public String getSchematicPath() { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean isSurfaceGateway() { - // TODO Auto-generated method stub + PocketManager.getDimensionData(world).createLink(x, y + 2, z, LinkTypes.DUNGEON, 0); + ItemDoor.placeDoorBlock(world, x, y + 1, z, 0, mod_pocketDim.transientDoor); return true; } @Override - public boolean areCoordsValid(World world, int x, int y, int z) { - // TODO Auto-generated method stub - return world.provider instanceof LimboProvider; + public boolean isLocationValid(World world, int x, int y, int z) { + return (world.provider instanceof LimboProvider); } - } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewaySandstonePillars.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewaySandstonePillars.java index cab1e12f..65e53a89 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewaySandstonePillars.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewaySandstonePillars.java @@ -1,61 +1,23 @@ package StevenDimDoors.mod_pocketDim.world.gateways; -import java.util.ArrayList; -import java.util.Random; - -import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; -import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; -import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; -import net.minecraft.block.Block; -import net.minecraft.world.World; -import net.minecraft.world.chunk.IChunkProvider; -public class GatewaySandstonePillars extends BaseGateway +public class GatewaySandstonePillars extends BaseSchematicGateway { - - private static final int GATEWAY_RADIUS = 4; - public GatewaySandstonePillars(DDProperties properties) { super(properties); - } + @Override - public boolean generate(World world, int x, int y, int z) + public String[] getBiomeKeywords() { - //simple to transform the generation location here. - //Do you think this is the best way to do this? - return super.generate(world, x, y+2, z); - } - @Override - public void generateRandomBits(World world, int x, int y, int z) - { - } - @Override - public DungeonPack getStartingPack() - { - return DungeonHelper.instance().getDungeonPack("RUINS"); - } - @Override - public String[] getBiomeNames() - { - return new String[]{"desert"}; + return new String[] { "desert" }; } + @Override public String getSchematicPath() { return "/schematics/gateways/sandstonePillars.schematic"; } - @Override - public boolean isSurfaceGateway() - { - return true; - } - @Override - public boolean areCoordsValid(World world, int x, int y, int z) { - // TODO Auto-generated method stub - return true; - } - } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayTwoPillars.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayTwoPillars.java index 9e1ea336..13507a40 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayTwoPillars.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayTwoPillars.java @@ -1,26 +1,20 @@ package StevenDimDoors.mod_pocketDim.world.gateways; -import java.util.ArrayList; - -import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.config.DDProperties; -import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; -import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; -import StevenDimDoors.mod_pocketDim.world.LimboProvider; import net.minecraft.block.Block; import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.config.DDProperties; -public class GatewayTwoPillars extends BaseGateway +public class GatewayTwoPillars extends BaseSchematicGateway { - private static final int GATEWAY_RADIUS = 4; public GatewayTwoPillars(DDProperties properties) { super(properties); } + @Override - void generateRandomBits(World world, int x, int y, int z) + protected void generateRandomBits(World world, int x, int y, int z) { final int blockID = Block.stoneBrick.blockID; @@ -32,48 +26,27 @@ public class GatewayTwoPillars extends BaseGateway //Check that the block is supported by an opaque block. //This prevents us from building over a cliff, on the peak of a mountain, //or the surface of the ocean or a frozen lake. - if (world.isBlockOpaqueCube(x + xc, y - 2, z + zc)) + if (world.isBlockOpaqueCube(x + xc, y - 1, z + zc)) { //Randomly choose whether to place bricks or not. The math is designed so that the //chances of placing a block decrease as we get farther from the gateway's center. if (Math.abs(xc) + Math.abs(zc) < world.rand.nextInt(2) + 3) { //Place Stone Bricks - world.setBlock(x + xc, y - 1, z + zc, blockID, 0, 3); + world.setBlock(x + xc, y, z + zc, blockID, 0, 3); } else if (Math.abs(xc) + Math.abs(zc) < world.rand.nextInt(3) + 3) { //Place Cracked Stone Bricks - world.setBlock(x + xc, y - 1, z + zc, blockID, 2, 3); + world.setBlock(x + xc, y, z + zc, blockID, 2, 3); } } } } } - @Override - public DungeonPack getStartingPack() { - // TODO Auto-generated method stub - return DungeonHelper.instance().getDungeonPack("RUINS"); - } - @Override - public String[] getBiomeNames() { - // TODO Auto-generated method stub - return null; - } + @Override public String getSchematicPath() { - // TODO Auto-generated method stub return "/schematics/gateways/twoPillars.schematic"; } - @Override - public boolean isSurfaceGateway() { - // TODO Auto-generated method stub - return true; - } - @Override - public boolean areCoordsValid(World world, int x, int y, int z) { - // TODO Auto-generated method stub - return !(world.provider instanceof LimboProvider); - } - } diff --git a/src/main/resources/assets/dimdoors/text/How_to_add_dungeons.txt b/src/main/resources/assets/dimdoors/text/How_to_add_dungeons.txt index c361d91f..254245c7 100644 --- a/src/main/resources/assets/dimdoors/text/How_to_add_dungeons.txt +++ b/src/main/resources/assets/dimdoors/text/How_to_add_dungeons.txt @@ -1,51 +1,70 @@ -Adding dungeons is pretty simple, but you have to know the various flags and stuff I use to read them in and build them. Ill walk you through the process here, and provide all the flags and a breif description of what they mean here. +This guide explains the simple details involved in creating your own dungeons. -To get started, run Minecraft with DimDoors installed and use the "/dd-create" command. +[CREATING YOUR BUILDING AREA] -This will generate an empty pocket dim for you to build with that is in the proper orientation (north). If you do not use this command, you WILL run into issues later. +To get started, run Minecraft with Dimensional Doors installed and use the command "/dd-create". This will create an empty pocket dimension for you to build in. It used to be necessary to use this command to ensure that the resulting room was oriented properly for exporting. That's no longer the case; you can now create pockets in any way and they'll also work fine. -So on to the building- You can ONLY use vanilla blocks in the dungeons. Everything that is not vanilla MC will be turned into fabric of reality when I gen them, or it will crash horribly. The only exceptions to this are DimDoors doors, which will be treated like mundane, vanilla doors of the same material. +[CHOOSING YOUR BUILDING MATERIALS] -The first step is to make your entrance door. This is where the player will appear when they teleport in for the first time. It is marked by a vanilla wooden door. It will be replaced by a wooden warp door on generation, and by default is set as the door you entered from. +You can ONLY build a dungeon using regular Minecraft blocks and some Dimensional Doors blocks. Everything that is not a regular Minecrat block or part of the acceptable Dimensional Doors blocks will be turned into Fabric of Reality during both exporting and importing of the dungeon. This is a safety precaution against potentially serious crashes. The permitted blocks from Dimensional Doors are: -As you build your dungeon, there are a few restrictions. Any chests you place will get filled with random loot, and not what you place in them. Any dispensers will get a few stacks of arrows. Other than that, any vanilla mechanics should work fine, except rails. I'm working on that now, as well as saving inventories. +Fabric of Reality, Ancient Fabric, Eternal Fabric, Warp Doors, Dimensional Doors, and Transient Doors -Any iron doors you place will become iron dim doors, and link to more dungeon pockets, so use these to make your dungeon lead farther into a dungeon chain. +Transient doors are only intended for use with Rift Gateway designs and may not be assigned a destination if loaded in a dungeon. Also note that rifts are not in the permitted list and will be filtered out. Entities (e.g. mobs, minecarts, items frames, and dropped items) will not be imported or exported either. -If you want your dungeon to link back the Overworld, place a wooden door on top of a Sandstone block. This will mark it as an exit door, and it will generate as a wooden Dim door leading to the Overworld (or whatever dim this chain started in). The sandstone block will become whatever is under it. +Previously, builders would have to use regular Minecraft doors and those would be converted into Warp Doors and Dimensional Doors when a design was imported. That behavior was changed to that players could use regular doors within their designs. All dimensional doors will be reset upon importing so creating paths within a single room is currently not possible. -Once you have finished creating your dungeon, you need to use the command "/dd-export " +[BUILDING YOUR DUNGEON] -To name it, use the following format: +The first step is to place the entrance door. That is where the player will appear when they teleport in for the first time. It is designated using a Warp Door. Any dungeon without an entrance door will fail to load. -___ +You can place Dimensinoal Doors to connect your room to other rooms. You only have to place the doors where you want them. The doors will be linked to other rooms automatically whenever a player steps through. -DungeonType: The dungeon types are "Hub", "SimpleHall", "ComplexHall", "Trap', "Maze", "Exit", and "DeadEnd'. +You can also place Warp Doors to act as exits to the Overworld and other dimensions. Their destinations will be assigned automatically whenever a player steps through. Note that there is an extra step involved for this. Any exit doors must have a block of regular sandstone underneath to make the proper entrance clear. If you forget to place the sandstone block, then the mod may select one of your exit doors as the entrance. The mod will also automatically replace the sandstone block with the block underneath it. - Hub: Dungeons that have 4 or more iron doors in them should be labeled as hubs, so they don't generate one after another. +Any empty chests or trapped chests will be loaded with loot automatically when the dungeon is imported. Chests or trapped chests with contents already will not be affected. Be sure not to leave loot inside your chests if you import and re-export any of your designs; this is a common mistake. - SimpleHall: Dungeons that contain a single iron door or two, but no more than that, and don't contain traps. These are the halls that separate rooms and should generally be tagged as 'closed'. +It used to be that empty dispensers would be filled automatically with a stack of arrows. That was needed before when loaded inventories could not be exported. Now that feature has been removed for added flexibility - in case someone needs to have empty dispensers in their designs. - ComplexHall: These dungeons are more like rooms and can be open. They can have piston puzzles or locks, and up to three iron doors. In addition, they can contain wooden doors to link to the surface. +Finally, End Portal Frame blocks act as special markers. When the dungeon is imported, the blocks are removed and Monoliths are spawned in their place. This is used to manually set up Monolith positions to ensure that certain areas of a dungeon are protected. It's not usually necessary to use those markers because have ways of assigning them random positions in a dungeon (explained below). - Trap: These dungeons are primarily traps and often contain only a single iron door. The traps should never instantly kill the player, and it should be possible to beat them. They can contain either a reward/chest, or simply allow progress. Piston traps are very fun for these. +[EXPORTING YOUR DUNGEON] - Maze: These dungeons can contain up to 3 iron doors. They can be simple labyrinths or full of changing walls, etc. They should not, however, be primarily trying to kill the player, though they can have possibly lethal elements. In the worst case, think of it as half trap and half hub. +Once you have finished creating your dungeon, you need to export it as a schematic file with the command "/dd-export [SpawnWeight]" - Exit: The main purpose of these dungeons is to link back to Overworld with a wooden door. They should never contain iron doors. +The mod searches a 101 x 101 x 101 block cube (centered on the player's position) for blocks and chooses the smallest area that contains all of the blocks it finds. That area is then exported. Be careful about leaving garbage outside of the pocket in which you were building since it will be detected and exported along with everything else. - DeadEnd: Dungeons that have no other doors except the entrance. Usually contain some sort of treasure. +The following section explains each parameter for the command. + +DungeonType: The dungeon types for the default Ruins are "Hub", "SimpleHall", "ComplexHall", "Trap", "Exit", and "DeadEnd". + + Hub: Dungeons that have 4 or more iron doors in them should be labeled as hubs, so they don't generate one after another. + + SimpleHall: Dungeons that contain one or two Dimensional Doors, but no more than that, and don't contain traps. These are the halls that separate rooms and are generally "closed" rooms. + + ComplexHall: These dungeons are more like rooms than hallways and can be open. They can have piston puzzles or locks, and up to three Dimensional Doors. In addition, they can contain wooden doors to link to the surface. + + Trap: These dungeons are primarily traps and often contain only a single iron door. The traps should never instantly kill the player, and it should be possible to beat them. They can contain either a reward/chest, or simply allow progress. Piston traps are very fun for these. + + Exit: The main purpose of these dungeons is to link back to Overworld with a wooden door. They should never contain iron doors. + + DeadEnd: Dungeons that have no other doors except the entrance. Usually contain some sort of treasure. + +Note that there used to be a Maze type as well. That type was changed for internal use. Dungeon types are specific to each dungeon pack and other type names may apply for other packs. IsOpen: Indicates whether the dungeon is an open-air structure or a closed structure that should be surrounded by Monoliths. Monoliths prevent players from breaking out of closed structures to avoid puzzles or traps. The only valid values are "open" or "closed". SpawnWeight: An optional integer that determines how frequently you want the dungeon to appear relative to others of the same type. The default weight is 100. Higher values cause a dungeon to generate more often, while lower values cause it to be less common. The minimum weight is 0 and the maximum weight is 10,000. +-------------------------- -Examples: - Hub_RuinsWithDoors_Open_100 - SimpleHall_WindingHallway_Closed_50 - Trap_CleverTrap_Closed +You can also use the command "/dd-export override" to force the mod to export your surroundings as a schematic without following the naming restrictions above. This is useful for exporting a dungeon with a dungeon type that isn't part of Ruins. + +Examples names: + Hub_RuinsWithDoors_Open_100 + SimpleHall_WindingHallway_Closed_50 + Trap_CleverTrap_Closed Although you can deviate from the format above, the current dungeon generation system requires that format to work properly. It will not select schematics that do not follow those naming rules. -Congratulations! You have added your own dungeon. You can use the command "/dd-rift " to generate it, or use "/dd-rift list" to list all available dungeons. Finally, "/dd-rift random" will select a dungeon at random. \ No newline at end of file +Congratulations! You have added your own dungeon. You can use the command "/dd-rift " to generate it, or use "/dd-list" to list all available dungeons. diff --git a/src/main/resources/schematics/balgor.txt b/src/main/resources/schematics/balgor.txt deleted file mode 100644 index b9d81571..00000000 --- a/src/main/resources/schematics/balgor.txt +++ /dev/null @@ -1,6 +0,0 @@ -/schematics/balgor/ComplexHall_GardenBalgor1_open_39.schematic -/schematics/balgor/ComplexHall_OpenHallBalgor1_Closed_68.schematic -/schematics/balgor/ComplexHall_SilverEggHallBalgor1_closed_25.schematic -/schematics/balgor/Maze_OmniMazeBalgor1_open_30.schematic -/schematics/balgor/Trap_ArrowTrapBalgor1_closed_20.schematic -/schematics/balgor/Trap_ZombieHallBalgor1_closed_25.schematic diff --git a/src/main/resources/schematics/balgor/ComplexHall_GardenBalgor1_open_39.schematic b/src/main/resources/schematics/balgor/ComplexHall_GardenBalgor1_open_39.schematic deleted file mode 100644 index fd5f9269..00000000 Binary files a/src/main/resources/schematics/balgor/ComplexHall_GardenBalgor1_open_39.schematic and /dev/null differ diff --git a/src/main/resources/schematics/balgor/ComplexHall_OpenHallBalgor1_Closed_68.schematic b/src/main/resources/schematics/balgor/ComplexHall_OpenHallBalgor1_Closed_68.schematic deleted file mode 100644 index 19be9c4f..00000000 Binary files a/src/main/resources/schematics/balgor/ComplexHall_OpenHallBalgor1_Closed_68.schematic and /dev/null differ diff --git a/src/main/resources/schematics/balgor/ComplexHall_SilverEggHallBalgor1_closed_25.schematic b/src/main/resources/schematics/balgor/ComplexHall_SilverEggHallBalgor1_closed_25.schematic deleted file mode 100644 index 270f0358..00000000 Binary files a/src/main/resources/schematics/balgor/ComplexHall_SilverEggHallBalgor1_closed_25.schematic and /dev/null differ diff --git a/src/main/resources/schematics/balgor/Maze_OmniMazeBalgor1_open_30.schematic b/src/main/resources/schematics/balgor/Maze_OmniMazeBalgor1_open_30.schematic deleted file mode 100644 index bffcbcfd..00000000 Binary files a/src/main/resources/schematics/balgor/Maze_OmniMazeBalgor1_open_30.schematic and /dev/null differ diff --git a/src/main/resources/schematics/balgor/Trap_ArrowTrapBalgor1_closed_20.schematic b/src/main/resources/schematics/balgor/Trap_ArrowTrapBalgor1_closed_20.schematic deleted file mode 100644 index 8ef105cd..00000000 Binary files a/src/main/resources/schematics/balgor/Trap_ArrowTrapBalgor1_closed_20.schematic and /dev/null differ diff --git a/src/main/resources/schematics/balgor/Trap_ZombieHallBalgor1_closed_25.schematic b/src/main/resources/schematics/balgor/Trap_ZombieHallBalgor1_closed_25.schematic deleted file mode 100644 index b968f0d9..00000000 Binary files a/src/main/resources/schematics/balgor/Trap_ZombieHallBalgor1_closed_25.schematic and /dev/null differ diff --git a/src/main/resources/schematics/balgor/rules.txt b/src/main/resources/schematics/balgor/rules.txt deleted file mode 100644 index bb4d683b..00000000 --- a/src/main/resources/schematics/balgor/rules.txt +++ /dev/null @@ -1,23 +0,0 @@ -Version 1 -Types: -Trap -ComplexHall -Maze - -Settings: -AllowDuplicatesInChain = false -AllowPackChangeOut = false -DistortDoorCoordinates = true - -## Prevent this pack from being selected for transitioning in once we've transitioned out -AllowPackChangeIn = true - -Rules: - -? ? ? -> - -? ? -> Maze#20 ComplexHall#40 Trap#40 - -? -> ComplexHall#40 Trap#60 - -->ComplexHall#100 \ No newline at end of file diff --git a/src/main/resources/schematics/ruins.txt b/src/main/resources/schematics/ruins.txt index f922cbbc..5e43921c 100644 --- a/src/main/resources/schematics/ruins.txt +++ b/src/main/resources/schematics/ruins.txt @@ -1,5 +1,7 @@ +/schematics/ruins/ComplexHall_Balgor0-CrumbledHall_Closed_75.schematic /schematics/ruins/complexHall_buggyTopEntry1_open_100.schematic /schematics/ruins/ComplexHall_Cere-PuzzleWall_Open_75.schematic +/schematics/ruins/ComplexHall_Cere-TransferTunnel_Closed_100.schematic /schematics/ruins/complexHall_exitRuinsWithHiddenDoor_open_100.schematic /schematics/ruins/complexHall_hallwayHiddenTreasure_closed_100.schematic /schematics/ruins/complexHall_largeBrokenHall_closed_100.schematic @@ -15,6 +17,7 @@ /schematics/ruins/complexHall_smallRotundaWithExit_closed_100.schematic /schematics/ruins/complexHall_tntPuzzleTrap_closed_50.schematic /schematics/ruins/deadEnd_azersDungeonO_closed_100.schematic +/schematics/ruins/DeadEnd_Balgor0-ArrowHall_Closed_75.schematic /schematics/ruins/deadEnd_brokenPillarsO_open_100.schematic /schematics/ruins/DeadEnd_Cere-FloatingAltar_Open_75.schematic /schematics/ruins/deadEnd_diamondTowerTemple1_open_100.schematic @@ -32,10 +35,14 @@ /schematics/ruins/deadEnd_tntTrapO_open_100.schematic /schematics/ruins/exit_exitCube_open_100.schematic /schematics/ruins/exit_lockingExitHall_closed_100.schematic +/schematics/ruins/Exit_SK-HotSuspense_Open_75.schematic /schematics/ruins/Exit_SK-LockingExitTrap_Closed_50.schematic /schematics/ruins/exit_smallExitPrison_open_100.schematic +/schematics/ruins/Exit_XombyCraft-RopeBridge_Open_100.schematic /schematics/ruins/hub_4WayBasicHall_closed_200.schematic /schematics/ruins/hub_4WayHallExit_closed_200.schematic +/schematics/ruins/Hub_Balgor0-OmniMaze_Open_50.schematic +/schematics/ruins/Hub_Cere-GreatHall_Open_40.schematic /schematics/ruins/hub_doorTotemRuins_open_100.schematic /schematics/ruins/hub_fortRuins_open_100.schematic /schematics/ruins/hub_hallwayTrapRooms1_closed_100.schematic @@ -61,12 +68,14 @@ /schematics/ruins/SimpleHall_SK-SpiralHallway_Open_100.schematic /schematics/ruins/SimpleHall_SK-UTurnLeft_Open_50.schematic /schematics/ruins/SimpleHall_SK-UTurnRight_Open_50.schematic +/schematics/ruins/SimpleHall_SK-WatchedForkLeft_Closed_80.schematic +/schematics/ruins/SimpleHall_SK-WatchedForkRight_Closed_80.schematic /schematics/ruins/simpleHall_smallSimpleLeft_closed_100.schematic /schematics/ruins/simpleHall_smallSimpleRight_closed_100.schematic /schematics/ruins/trap_fakeTNTTrap_closed_100.schematic /schematics/ruins/trap_hallwayPitFallTrap_closed_200.schematic /schematics/ruins/trap_lavaPyramid_open_100.schematic -/schematics/ruins/trap_pistonFallRuins_open_100.schematic +/schematics/ruins/trap_pistonFallRuins_open_75.schematic /schematics/ruins/trap_pistonFloorHall_closed_150.schematic /schematics/ruins/trap_pistonFloorPlatform2_closed_100.schematic /schematics/ruins/trap_pistonFloorPlatform_closed_100.schematic diff --git a/src/main/resources/schematics/ruins/ComplexHall_Balgor0-CrumbledHall_Closed_75.schematic b/src/main/resources/schematics/ruins/ComplexHall_Balgor0-CrumbledHall_Closed_75.schematic new file mode 100644 index 00000000..7f924f63 Binary files /dev/null and b/src/main/resources/schematics/ruins/ComplexHall_Balgor0-CrumbledHall_Closed_75.schematic differ diff --git a/src/main/resources/schematics/ruins/ComplexHall_Cere-JumpPass_Open_75.schematic b/src/main/resources/schematics/ruins/ComplexHall_Cere-JumpPass_Open_75.schematic new file mode 100644 index 00000000..9c242b63 Binary files /dev/null and b/src/main/resources/schematics/ruins/ComplexHall_Cere-JumpPass_Open_75.schematic differ diff --git a/src/main/resources/schematics/ruins/ComplexHall_Cere-TransferTunnel_Closed_100.schematic b/src/main/resources/schematics/ruins/ComplexHall_Cere-TransferTunnel_Closed_100.schematic new file mode 100644 index 00000000..786a0107 Binary files /dev/null and b/src/main/resources/schematics/ruins/ComplexHall_Cere-TransferTunnel_Closed_100.schematic differ diff --git a/src/main/resources/schematics/ruins/DeadEnd_Balgor0-ArrowHall_Closed_75.schematic b/src/main/resources/schematics/ruins/DeadEnd_Balgor0-ArrowHall_Closed_75.schematic new file mode 100644 index 00000000..12855b2e Binary files /dev/null and b/src/main/resources/schematics/ruins/DeadEnd_Balgor0-ArrowHall_Closed_75.schematic differ diff --git a/src/main/resources/schematics/ruins/DeadEnd_Floating-Altar_Open_100.schematic b/src/main/resources/schematics/ruins/DeadEnd_Floating-Altar_Open_100.schematic deleted file mode 100644 index fa5b3c02..00000000 Binary files a/src/main/resources/schematics/ruins/DeadEnd_Floating-Altar_Open_100.schematic and /dev/null differ diff --git a/src/main/resources/schematics/ruins/Exit_SK-HotSuspense_Open_75.schematic b/src/main/resources/schematics/ruins/Exit_SK-HotSuspense_Open_75.schematic new file mode 100644 index 00000000..b658c79f Binary files /dev/null and b/src/main/resources/schematics/ruins/Exit_SK-HotSuspense_Open_75.schematic differ diff --git a/src/main/resources/schematics/ruins/Exit_XombyCraft-RopeBridge_Open_100.schematic b/src/main/resources/schematics/ruins/Exit_XombyCraft-RopeBridge_Open_100.schematic new file mode 100644 index 00000000..d4278899 Binary files /dev/null and b/src/main/resources/schematics/ruins/Exit_XombyCraft-RopeBridge_Open_100.schematic differ diff --git a/src/main/resources/schematics/ruins/Hub_Balgor0-OmniMaze_Open_50.schematic b/src/main/resources/schematics/ruins/Hub_Balgor0-OmniMaze_Open_50.schematic new file mode 100644 index 00000000..077e4e70 Binary files /dev/null and b/src/main/resources/schematics/ruins/Hub_Balgor0-OmniMaze_Open_50.schematic differ diff --git a/src/main/resources/schematics/ruins/Hub_Cere-GreatHall_Open_40.schematic b/src/main/resources/schematics/ruins/Hub_Cere-GreatHall_Open_40.schematic new file mode 100644 index 00000000..e639e589 Binary files /dev/null and b/src/main/resources/schematics/ruins/Hub_Cere-GreatHall_Open_40.schematic differ diff --git a/src/main/resources/schematics/ruins/Hub_SK-FractalCage_Open_40.schematic b/src/main/resources/schematics/ruins/Hub_SK-FractalCage_Open_40.schematic index 5a0c61c4..db1ceaf0 100644 Binary files a/src/main/resources/schematics/ruins/Hub_SK-FractalCage_Open_40.schematic and b/src/main/resources/schematics/ruins/Hub_SK-FractalCage_Open_40.schematic differ diff --git a/src/main/resources/schematics/ruins/Hub_SK-RandomSnow_Open_75.schematic b/src/main/resources/schematics/ruins/Hub_SK-RandomSnow_Open_75.schematic index 18503e16..5a4a0cef 100644 Binary files a/src/main/resources/schematics/ruins/Hub_SK-RandomSnow_Open_75.schematic and b/src/main/resources/schematics/ruins/Hub_SK-RandomSnow_Open_75.schematic differ diff --git a/src/main/resources/schematics/ruins/Hub_SK-RandomSwamp_Open_75.schematic b/src/main/resources/schematics/ruins/Hub_SK-RandomSwamp_Open_75.schematic index 5f3b18da..b3a086e0 100644 Binary files a/src/main/resources/schematics/ruins/Hub_SK-RandomSwamp_Open_75.schematic and b/src/main/resources/schematics/ruins/Hub_SK-RandomSwamp_Open_75.schematic differ diff --git a/src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkLeft_Closed_80.schematic b/src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkLeft_Closed_80.schematic new file mode 100644 index 00000000..4601cc00 Binary files /dev/null and b/src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkLeft_Closed_80.schematic differ diff --git a/src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkRight_Closed_80.schematic b/src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkRight_Closed_80.schematic new file mode 100644 index 00000000..d5be6664 Binary files /dev/null and b/src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkRight_Closed_80.schematic differ diff --git a/src/main/resources/schematics/ruins/Trap_SK-RaceTheLight_Closed_50.schematic b/src/main/resources/schematics/ruins/Trap_SK-RaceTheLight_Closed_50.schematic index 44df5265..8206a43e 100644 Binary files a/src/main/resources/schematics/ruins/Trap_SK-RaceTheLight_Closed_50.schematic and b/src/main/resources/schematics/ruins/Trap_SK-RaceTheLight_Closed_50.schematic differ diff --git a/src/main/resources/schematics/ruins/rules.txt b/src/main/resources/schematics/ruins/rules.txt index a14fe17d..06188586 100644 --- a/src/main/resources/schematics/ruins/rules.txt +++ b/src/main/resources/schematics/ruins/rules.txt @@ -16,6 +16,8 @@ DistortDoorCoordinates = true ## Prevent this pack from being selected for transitioning in once we've transitioned out AllowPackChangeIn = false +DuplicateSearchLevels = 1 + Rules: Exit -> DeadEnd Exit diff --git a/src/main/resources/schematics/ruins/trap_pistonFallRuins_open_100.schematic b/src/main/resources/schematics/ruins/trap_pistonFallRuins_open_100.schematic deleted file mode 100644 index ca2d664a..00000000 Binary files a/src/main/resources/schematics/ruins/trap_pistonFallRuins_open_100.schematic and /dev/null differ diff --git a/src/main/resources/schematics/ruins/trap_pistonFallRuins_open_75.schematic b/src/main/resources/schematics/ruins/trap_pistonFallRuins_open_75.schematic new file mode 100644 index 00000000..0ed8a39e Binary files /dev/null and b/src/main/resources/schematics/ruins/trap_pistonFallRuins_open_75.schematic differ