Basic Configurable Dungeon Chains

Completed a basic version of configurable dungeon chains. Almost all of
the final funcionality is present. However, the configuration is
hardcoded at the moment, not read from a file. This was done for testing
purposes. I'll add reading from config files soon.

Dungeon packs are partially implemented. Built-in and custom dungeons
are currently thrown into the default pack, Ruins. The next step is to
generalize the dungeon registration code in DungeonHelper so that we can
detect dungeon packs, read their config files, and register dungeons
with their corresponding pack. dd-export will need to support packs as
well. dd-rift will have issues dealing with duplicate dungeon names
across packs, but this isn't a major concern and can be dealt with in
the long term.
This commit is contained in:
SenseiKiwi 2013-08-05 20:16:45 -04:00
parent 35329f9024
commit f372b9ccb5
7 changed files with 180 additions and 28 deletions

View file

@ -43,12 +43,15 @@ public class SchematicLoader
if (dimList.get(destDimID).dungeonGenerator == null)
{
//The following initialization code is based on code from ChunkProviderGenerate.
//It makes our generation depend on the world seed.
//It makes our generation depend on the world seed. We have an additional seed here
//to prevent correlations between the selected dungeons and the locations of gateways.
//TODO: We should centralize RNG initialization and world-seed modifiers for each specific application.
Random random = new Random(world.getSeed());
long factorA = random.nextLong() / 2L * 2L + 1L;
long factorB = random.nextLong() / 2L * 2L + 1L;
random.setSeed((link.destXCoord >> 4) * factorA + (link.destZCoord >> 4) * factorB ^ world.getSeed());
final long localSeed = world.getSeed() ^ 0x2F50DB9B4A8057E4L;
final Random random = new Random();
final long factorA = random.nextLong() / 2L * 2L + 1L;
final long factorB = random.nextLong() / 2L * 2L + 1L;
random.setSeed((link.destXCoord >> 4) * factorA + (link.destZCoord >> 4) * factorB ^ localSeed);
dungeonHelper.generateDungeonLink(link, dungeonHelper.RuinsPack, random);
}

View file

@ -15,12 +15,13 @@ public class DungeonChainRule
ArrayList<String> conditionNames = source.getCondition();
ArrayList<WeightedContainer<String>> productNames = source.getProducts();
//Obtain the IDs of dungeon types in reverse order. Reverse order makes comparing against chain histories easy.
condition = new int[conditionNames.size()];
for (int k = 0; k < condition.length; k++)
for (int src = 0, dst = condition.length - 1; src < condition.length; src++, dst--)
{
condition[k] = nameToTypeMapping.get(conditionNames.get(k)).ID;
condition[dst] = nameToTypeMapping.get(conditionNames.get(src)).ID;
}
products = new ArrayList<WeightedContainer<DungeonType>>();
products = new ArrayList<WeightedContainer<DungeonType>>(productNames.size());
for (WeightedContainer<String> product : productNames)
{
products.add(new WeightedContainer<DungeonType>(nameToTypeMapping.get(product.getData()), product.itemWeight ));

View file

@ -162,11 +162,11 @@ public class DungeonPack
{
excludedDungeons = new HashSet<DungeonGenerator>(history);
}
//List which dungeons are allowed
ArrayList<DungeonGenerator> candidates;
ArrayList<DungeonGenerator> group = groupedDungeons.get(nextType.ID);
if (excludedDungeons != null)
if (excludedDungeons != null && !excludedDungeons.isEmpty())
{
candidates = new ArrayList<DungeonGenerator>(group.size());
for (DungeonGenerator dungeon : group)

View file

@ -9,7 +9,9 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import java.util.regex.Pattern;
@ -423,32 +425,72 @@ public class DungeonHelper
//manipulate the output of this function by setting up links to mislead our algorithm or by removing links.
//Dimensions MUST have built-in records of their parent dimensions in the future. ~SenseiKiwi
dimHelper helper = dimHelper.instance;
ArrayList<DungeonGenerator> history = new ArrayList<DungeonGenerator>();
DimData tailDim = helper.getDimData(helper.getLinkDataFromCoords(dimData.exitDimLink.destXCoord, dimData.exitDimLink.destYCoord, dimData.exitDimLink.destZCoord, dimData.exitDimLink.destDimID).destDimID);
DimData tailDim = dimData;
boolean found = true;
for (int count = 0; count < maxSize; count++)
if (dimData.dungeonGenerator == null || dimData.dungeonGenerator.getDungeonType().Owner != pack || maxSize < 1)
{
if (tailDim.dungeonGenerator == null || tailDim.dungeonGenerator.getDungeonType().Owner != pack)
//The initial dimension is already outside our pack. Return an empty list.
return history;
}
history.add(dimData.dungeonGenerator);
for (int count = 1; count < maxSize && found; count++)
{
found = false;
for (LinkData link : tailDim.getLinksInDim())
{
//We've reached a dimension that doesn't belong to our pack. Stop the search here.
break;
}
history.add(tailDim.dungeonGenerator);
if (count + 1 < maxSize)
{
for (LinkData link : tailDim.getLinksInDim())
DimData neighbor = dimHelper.instance.getDimData(link.destDimID);
if (neighbor.depth == tailDim.depth - 1 && neighbor.dungeonGenerator != null &&
neighbor.dungeonGenerator.getDungeonType().Owner == pack)
{
DimData nextDim = dimHelper.instance.getDimData(link.destDimID);
if (helper.getDimDepth(link.destDimID) == tailDim.depth + 1)
{
tailDim = nextDim;
break;
}
tailDim = neighbor;
history.add(tailDim.dungeonGenerator);
found = true;
break;
}
}
}
return history;
}
public static ArrayList<DungeonGenerator> getFlatDungeonTree(DimData dimData, int maxSize)
{
//TODO: I've improved this code for the time being. However, searching across links is a flawed approach. A player could
//manipulate the output of this function by setting up links to mislead our algorithm or by removing links.
//Dimensions MUST have built-in records of their parent dimensions in the future. ~SenseiKiwi
dimHelper helper = dimHelper.instance;
ArrayList<DungeonGenerator> dungeons = new ArrayList<DungeonGenerator>();
DimData root = helper.getDimData(helper.getLinkDataFromCoords(dimData.exitDimLink.destXCoord, dimData.exitDimLink.destYCoord, dimData.exitDimLink.destZCoord, dimData.exitDimLink.destDimID).destDimID);
HashSet<DimData> checked = new HashSet<DimData>();
Queue<DimData> pendingDimensions = new LinkedList<DimData>();
if (root.dungeonGenerator == null)
{
return dungeons;
}
pendingDimensions.add(root);
checked.add(root);
while (dungeons.size() < maxSize && !pendingDimensions.isEmpty())
{
DimData current = pendingDimensions.remove();
for (LinkData link : current.getLinksInDim())
{
DimData child = helper.getDimData(link.destDimID);
if (child.depth == current.depth + 1 && child.dungeonGenerator != null && checked.add(child))
{
dungeons.add(child.dungeonGenerator);
pendingDimensions.add(child);
}
if (dungeons.size() == maxSize)
{
break;
}
}
}
return dungeons;
}
}

View file

@ -0,0 +1,52 @@
package StevenDimDoors.mod_pocketDim.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public abstract class BaseConfigurationProcessor<T>
{
public BaseConfigurationProcessor() { }
public boolean canRead()
{
return true;
}
public boolean canWrite()
{
return true;
}
public T readFromFile(String path) throws FileNotFoundException, ConfigurationProcessingException
{
return readFromFile(new File(path));
}
public T readFromFile(File file) throws FileNotFoundException, ConfigurationProcessingException
{
return readFromStream(new FileInputStream(file));
}
public T readFromResource(String resourcePath) throws ConfigurationProcessingException
{
return readFromStream(this.getClass().getResourceAsStream(resourcePath));
}
public abstract T readFromStream(InputStream inputStream) throws ConfigurationProcessingException;
public void writeToFile(File file, T data) throws FileNotFoundException, ConfigurationProcessingException
{
writeToStream(new FileOutputStream(file), data);
}
public void writeToFile(String path, T data) throws FileNotFoundException, ConfigurationProcessingException
{
writeToFile(new File(path), data);
}
public abstract void writeToStream(OutputStream outputStream, T data) throws ConfigurationProcessingException;
}

View file

@ -0,0 +1,21 @@
package StevenDimDoors.mod_pocketDim.util;
public class ConfigurationProcessingException extends Exception
{
private static final long serialVersionUID = -4525298050874891911L;
public ConfigurationProcessingException()
{
super();
}
public ConfigurationProcessingException(String message)
{
super(message);
}
public ConfigurationProcessingException(String message, Throwable cause)
{
super(message, cause);
}
}

View file

@ -0,0 +1,33 @@
Version 1
Types:
Hub
Trap
SimpleHall
ComplexHall
Exit
DeadEnd
Maze
Settings:
AllowRepetitionsInBranch = false
AllowPackChangeOut = true
AllowPackChangeIn = true
PackWeight = 100
Rules:
Exit -> DeadEnd Exit
DeadEnd -> DeadEnd Exit
? ? ? ? ? ? ? ? -> Trap#20 SimpleHall#40 ComplexHall#10 Exit#20 DeadEnd#10
? ? ? ? -> Trap#18 SimpleHall#40 ComplexHall#10 Exit#18 DeadEnd#10 Hub#4
? ? ? -> ComplexHall Hub Trap SimpleHall Maze
? ? -> ComplexHall Hub Trap SimpleHall Maze
? -> ComplexHall#40 Hub#30 Trap#10 SimpleHall#10 Maze#10
-> ComplexHall#40 Hub#30 Trap#10 SimpleHall#10 Maze#10