Merge pull request #144 from SenseiKiwi/master

Various Updates
This commit is contained in:
StevenRS11 2014-03-24 14:45:47 -04:00
commit 12e0fee70a
56 changed files with 579 additions and 573 deletions

View file

@ -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");
}
}
}
}
}

View file

@ -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<Integer> 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;
}
}

View file

@ -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
{

View file

@ -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
{

View file

@ -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();

View file

@ -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

View file

@ -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));
}
}

View file

@ -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;
}

View file

@ -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<String, DungeonType> 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<DungeonData> history = DungeonHelper.getDungeonChainHistory(dimension, this, maxSearchLength);
return getNextDungeon(history, random);
ArrayList<DungeonData> history = DungeonHelper.getDungeonChainHistory(parent, this, maxSearchLength);
ArrayList<DungeonData> 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<DungeonData>();
}
subtreeHistory = new ArrayList<DungeonData>();
return getNextDungeon(history, subtreeHistory, random);
}
private DungeonData getNextDungeon(ArrayList<DungeonData> history, Random random)
private DungeonData getNextDungeon(ArrayList<DungeonData> history, ArrayList<DungeonData> 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<DungeonData> 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<DungeonData>(history);
if (config.allowDuplicatesInChain())
{
excludedDungeons = new HashSet<DungeonData>(subtreeHistory);
excludedDungeons.addAll(subtreeHistory);
}
else
{
excludedDungeons = new HashSet<DungeonData>(2 * (history.size() + subtreeHistory.size()));
excludedDungeons.addAll(history);
excludedDungeons.addAll(subtreeHistory);
}
}
//List which dungeons are allowed

View file

@ -11,6 +11,7 @@ public class DungeonPackConfig
private boolean allowPackChangeOut;
private boolean distortDoorCoordinates;
private int packWeight;
private int duplicateSearchLevels;
private ArrayList<DungeonChainRuleDefinition> 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<DungeonChainRuleDefinition>) 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;

View file

@ -35,6 +35,8 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
private final int DEFAULT_PRODUCT_WEIGHT = 100;
private final int MAX_DUNGEON_PACK_WEIGHT = 10000;
private final int MIN_DUNGEON_PACK_WEIGHT = 1;
private final int MAX_DUPLICATE_SEARCH_LEVELS = 5;
private final int MIN_DUPLICATE_SEARCH_LEVELS = 0;
private final int DEFAULT_DUNGEON_PACK_WEIGHT = 100;
private final int MAX_CONDITION_LENGTH = 20;
private final int MAX_PRODUCT_COUNT = MAX_CONDITION_LENGTH;
@ -80,6 +82,7 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
config.setAllowPackChangeOut(true);
config.setDistortDoorCoordinates(false);
config.setPackWeight(DEFAULT_DUNGEON_PACK_WEIGHT);
config.setDuplicateSearchLevels(MIN_DUPLICATE_SEARCH_LEVELS);
//Read the settings section
if (findSection("Settings", reader))
@ -273,6 +276,18 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
valid = false;
}
}
else if (name.equalsIgnoreCase("DuplicateSearchLevels"))
{
int levels = Integer.parseInt(value);
if (levels >= MIN_DUPLICATE_SEARCH_LEVELS && levels <= MAX_DUPLICATE_SEARCH_LEVELS)
{
config.setDuplicateSearchLevels(levels);
}
else
{
valid = false;
}
}
else
{
valid = false;

View file

@ -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<String> schematics, boolean isInternal, boolean verbose, DungeonPackConfigReader reader)
private DungeonPack registerDungeonPack(String directory, Iterable<String> 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<DungeonData> 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<String> schematics = new ArrayList<String>();
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<String> schematics = new ArrayList<String>();
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<DungeonData> 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<DungeonData> 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<DungeonData>();
}
int count = 0;
NewDimData tail = dimension.parent();
DungeonData dungeon = tail.dungeon();
NewDimData current = start;
DungeonData dungeon = current.dungeon();
ArrayList<DungeonData> history = new ArrayList<DungeonData>();
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<DungeonData> 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<DungeonData> listDungeonsInTree(NewDimData root, DungeonPack pack, int maxSize)
{
NewDimData root = dimension;
int count = 0;
NewDimData current;
DungeonData dungeon;
ArrayList<DungeonData> dungeons = new ArrayList<DungeonData>();
Queue<NewDimData> pendingDimensions = new LinkedList<NewDimData>();
if (root.dungeon() == null)
{
return dungeons;
}
Queue<NewDimData> pendingDimensions = new LinkedList<NewDimData>();
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 <code>null</code> 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;
}
}

View file

@ -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.");
}
}
}

View file

@ -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");

View file

@ -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;
}

View file

@ -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));
}
}

View file

@ -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);
}
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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<DungeonData, DungeonSchematic> 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<DungeonData, DungeonSchematic> 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<DungeonData, DungeonSchematic> selectDungeon(NewDimData dimension, Random random, DDProperties properties)
private static Pair<DungeonData, DungeonSchematic> 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)
{

View file

@ -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)

View file

@ -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 <code>true</code> true if the specified biome is a valid for generating this gateway, otherwise <code>false</code>
*/
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 <code>true</code> if the location is valid, otherwise <code>false</code>
*/
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[] { "" };
}
}

View file

@ -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();
}

View file

@ -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<BaseGateway> 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<BaseGateway> validGateways = new ArrayList<BaseGateway>();
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);
}
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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 <fileName>"
[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.
<DungeonType>_<DungeonName>_<IsOpen>_<SpawnWeight>
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 <DungeonType> <DungeonName> <IsOpen> [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 <fileName> 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 <dungeonName>" to generate it, or use "/dd-rift list" to list all available dungeons. Finally, "/dd-rift random" will select a dungeon at random.
Congratulations! You have added your own dungeon. You can use the command "/dd-rift <dungeonName>" to generate it, or use "/dd-list" to list all available dungeons.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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