Progress on Implementing Dungeon Packs
1. Integrated support for dungeon pack config options into the code (i.e. we actually DO what the settings specify) 2. Added random transitions from one dungeon type to another. Dungeons might also begin with a non-default pack. 3. Fixed a config reading bug that caused settings to be ignored and some invalid settings wouldn't trigger exceptions. Also fixed other dungeon pack bugs.
This commit is contained in:
@@ -167,7 +167,7 @@ public class DungeonSchematic extends Schematic {
|
||||
return new DungeonSchematic(Schematic.copyFromWorld(world, x, y, z, width, height, length, doCompactBounds));
|
||||
}
|
||||
|
||||
public void copyToWorld(World world, Point3D pocketCenter, int dungeonOrientation, int originDimID, int destDimID)
|
||||
public void copyToWorld(World world, Point3D pocketCenter, int dungeonOrientation, int originDimID, int destDimID, boolean doDistortCoordinates)
|
||||
{
|
||||
//TODO: This function is an improvised solution so we can get the release moving. In the future,
|
||||
//we should generalize block tranformations and implement support for them at the level of Schematic,
|
||||
@@ -222,17 +222,17 @@ public class DungeonSchematic extends Schematic {
|
||||
world.setBlockTileEntity(pocketPoint.getX(), pocketPoint.getY(), pocketPoint.getZ(), TileEntity.createAndLoadEntity(tileTag));
|
||||
}
|
||||
|
||||
setUpDungeon(world, pocketCenter, turnAngle, originDimID, destDimID);
|
||||
setUpDungeon(world, pocketCenter, turnAngle, originDimID, destDimID, doDistortCoordinates);
|
||||
}
|
||||
|
||||
private void setUpDungeon(World world, Point3D pocketCenter, int turnAngle, int originDimID, int destDimID)
|
||||
private void setUpDungeon(World world, Point3D pocketCenter, int turnAngle, int originDimID, int destDimID, boolean doDistortCoordinates)
|
||||
{
|
||||
//The following Random initialization code is based on code from ChunkProviderGenerate.
|
||||
//It makes our generation depend on the world seed.
|
||||
Random random = new Random(world.getSeed());
|
||||
long factorA = random.nextLong() / 2L * 2L + 1L;
|
||||
long factorB = random.nextLong() / 2L * 2L + 1L;
|
||||
random.setSeed((pocketCenter.getX() >> 4) * factorA + (pocketCenter.getZ() >> 4) * factorB ^ world.getSeed());
|
||||
random.setSeed(pocketCenter.getX() * factorB + pocketCenter.getZ() * factorA ^ world.getSeed());
|
||||
|
||||
//Transform dungeon corners
|
||||
Point3D minCorner = new Point3D(0, 0, 0);
|
||||
@@ -249,7 +249,7 @@ public class DungeonSchematic extends Schematic {
|
||||
//Set up link data for dimensional doors
|
||||
for (Point3D location : dimensionalDoorLocations)
|
||||
{
|
||||
setUpDimensionalDoorLink(world, location, entranceDoorLocation, turnAngle, pocketCenter, originDimID, destDimID, random);
|
||||
setUpDimensionalDoorLink(world, location, entranceDoorLocation, turnAngle, pocketCenter, originDimID, destDimID, doDistortCoordinates, random);
|
||||
}
|
||||
|
||||
//Set up link data for exit door
|
||||
@@ -374,11 +374,22 @@ public class DungeonSchematic extends Schematic {
|
||||
}
|
||||
}
|
||||
|
||||
private static void setUpDimensionalDoorLink(World world, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter, int originDimID, int destDimID, Random random)
|
||||
private static void setUpDimensionalDoorLink(World world, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter, int originDimID, int destDimID, boolean applyNoise, Random random)
|
||||
{
|
||||
int depth = dimHelper.instance.getDimDepth(originDimID) + 1;
|
||||
int forwardNoise = MathHelper.getRandomIntegerInRange(random, -50 * depth, 150 * depth);
|
||||
int sidewaysNoise = MathHelper.getRandomIntegerInRange(random, -10 * depth, 10 * depth);
|
||||
int forwardNoise;
|
||||
int sidewaysNoise;
|
||||
|
||||
if (applyNoise)
|
||||
{
|
||||
forwardNoise = MathHelper.getRandomIntegerInRange(random, -50 * depth, 150 * depth);
|
||||
sidewaysNoise = MathHelper.getRandomIntegerInRange(random, -10 * depth, 10 * depth);
|
||||
}
|
||||
else
|
||||
{
|
||||
forwardNoise = 0;
|
||||
sidewaysNoise = 0;
|
||||
}
|
||||
|
||||
//Transform doorLocation to the pocket coordinate system
|
||||
Point3D location = point.clone();
|
||||
|
||||
@@ -11,9 +11,32 @@ public class DungeonChainRule
|
||||
private final ArrayList<WeightedContainer<DungeonType>> products;
|
||||
|
||||
public DungeonChainRule(DungeonChainRuleDefinition source, HashMap<String, DungeonType> nameToTypeMapping)
|
||||
{
|
||||
{
|
||||
ArrayList<String> conditionNames = source.getCondition();
|
||||
ArrayList<WeightedContainer<String>> productNames = source.getProducts();
|
||||
|
||||
//Validate the data, just in case
|
||||
if (conditionNames == null)
|
||||
{
|
||||
throw new NullPointerException("source cannot have null conditions");
|
||||
}
|
||||
if (productNames == null)
|
||||
{
|
||||
throw new NullPointerException("source cannot have null products");
|
||||
}
|
||||
if (productNames.isEmpty())
|
||||
{
|
||||
throw new IllegalArgumentException("products cannot be an empty list");
|
||||
}
|
||||
for (WeightedContainer<String> product : productNames)
|
||||
{
|
||||
//Check for weights less than 1. Those could cause Minecraft's random selection algorithm to throw an exception.
|
||||
//At the very least, they're useless values.
|
||||
if (product.itemWeight < 1)
|
||||
{
|
||||
throw new IllegalArgumentException("products cannot contain items with weights less than 1");
|
||||
}
|
||||
}
|
||||
|
||||
//Obtain the IDs of dungeon types in reverse order. Reverse order makes comparing against chain histories easy.
|
||||
condition = new int[conditionNames.size()];
|
||||
|
||||
@@ -11,6 +11,25 @@ public class DungeonChainRuleDefinition
|
||||
|
||||
public DungeonChainRuleDefinition(ArrayList<String> conditions, ArrayList<WeightedContainer<String>> products)
|
||||
{
|
||||
//Validate the arguments, just in case
|
||||
if (conditions == null)
|
||||
{
|
||||
throw new NullPointerException("conditions cannot be null");
|
||||
}
|
||||
if (products.isEmpty())
|
||||
{
|
||||
throw new IllegalArgumentException("products cannot be an empty list");
|
||||
}
|
||||
for (WeightedContainer<String> product : products)
|
||||
{
|
||||
//Check for weights less than 1. Those could cause Minecraft's random selection algorithm to throw an exception.
|
||||
//At the very least, they're useless values.
|
||||
if (product.itemWeight < 1)
|
||||
{
|
||||
throw new IllegalArgumentException("products cannot contain items with weights less than 1");
|
||||
}
|
||||
}
|
||||
|
||||
this.conditions = conditions;
|
||||
this.products = products;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ public class DungeonPack
|
||||
//The ID numbers would be a problem since it couldn't have a valid number, since it wasn't initialized by the pack instance.
|
||||
//FIXME: Do not release this code as an update without dealing with disowned types!
|
||||
|
||||
private static final int MAX_HISTORY_LENGTH = 1337;
|
||||
|
||||
private final String name;
|
||||
private final HashMap<String, DungeonType> nameToTypeMapping;
|
||||
private final ArrayList<ArrayList<DungeonGenerator>> groupedDungeons;
|
||||
@@ -78,6 +80,11 @@ public class DungeonPack
|
||||
return name;
|
||||
}
|
||||
|
||||
public DungeonPackConfig getConfig()
|
||||
{
|
||||
return config.clone();
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return allDungeons.isEmpty();
|
||||
@@ -128,7 +135,7 @@ public class DungeonPack
|
||||
//of the longest rule we have. Getting any more data would be useless. This optimization could be significant
|
||||
//for dungeon packs that can extend arbitrarily deep. We should probably set a reasonable limit anyway.
|
||||
|
||||
int maxSearchLength = config.allowDuplicatesInChain() ? maxRuleLength : 1337;
|
||||
int maxSearchLength = config.allowDuplicatesInChain() ? maxRuleLength : MAX_HISTORY_LENGTH;
|
||||
ArrayList<DungeonGenerator> history = DungeonHelper.getDungeonChainHistory(
|
||||
dimHelper.instance.getDimData(inbound.locDimID), this, maxSearchLength);
|
||||
return getNextDungeon(history, random);
|
||||
|
||||
@@ -18,14 +18,14 @@ public class DungeonPackConfig
|
||||
@SuppressWarnings("unchecked")
|
||||
private DungeonPackConfig(DungeonPackConfig source)
|
||||
{
|
||||
this.name = source.name;
|
||||
this.typeNames = (ArrayList<String>) source.typeNames.clone();
|
||||
this.name = (source.name != null) ? source.name : null;
|
||||
this.typeNames = (source.typeNames != null) ? (ArrayList<String>) source.typeNames.clone() : null;
|
||||
this.allowDuplicatesInChain = source.allowDuplicatesInChain;
|
||||
this.allowPackChangeIn = source.allowPackChangeIn;
|
||||
this.allowPackChangeOut = source.allowPackChangeOut;
|
||||
this.distortDoorCoordinates = source.distortDoorCoordinates;
|
||||
this.packWeight = source.packWeight;
|
||||
this.rules = (ArrayList<DungeonChainRuleDefinition>) source.rules.clone();
|
||||
this.rules = (source.rules != null) ? (ArrayList<DungeonChainRuleDefinition>) source.rules.clone() : null;
|
||||
}
|
||||
|
||||
public void validate()
|
||||
@@ -114,7 +114,7 @@ public class DungeonPackConfig
|
||||
this.packWeight = packWeight;
|
||||
}
|
||||
|
||||
public boolean getDistortDoorCoordinates()
|
||||
public boolean doDistortDoorCoordinates()
|
||||
{
|
||||
return distortDoorCoordinates;
|
||||
}
|
||||
|
||||
@@ -31,9 +31,13 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
|
||||
private final int CONFIG_VERSION = 1;
|
||||
private final int LOOKAHEAD_LIMIT = 1024;
|
||||
private final int MAX_PRODUCT_WEIGHT = 10000;
|
||||
private final int MIN_PRODUCT_WEIGHT = 1;
|
||||
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 DEFAULT_DUNGEON_PACK_WEIGHT = 100;
|
||||
private final int MAX_CONDITION_LENGTH = 20;
|
||||
private final int MAX_PRODUCT_COUNT = MAX_CONDITION_LENGTH;
|
||||
private final String COMMENT_MARKER = "##";
|
||||
|
||||
private final Pattern DUNGEON_TYPE_PATTERN = Pattern.compile("[A-Za-z0-9_\\-]{1,20}");
|
||||
@@ -237,8 +241,8 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
|
||||
{
|
||||
try
|
||||
{
|
||||
String name = settingParts[0];
|
||||
String value = settingParts[1];
|
||||
String name = settingParts[0].trim();
|
||||
String value = settingParts[1].trim();
|
||||
if (name.equalsIgnoreCase("AllowDuplicatesInChain"))
|
||||
{
|
||||
config.setAllowDuplicatesInChain(parseBoolean(value));
|
||||
@@ -258,7 +262,7 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
|
||||
else if (name.equalsIgnoreCase("PackWeight"))
|
||||
{
|
||||
int weight = Integer.parseInt(value);
|
||||
if (weight >= 0 && weight <= MAX_DUNGEON_PACK_WEIGHT)
|
||||
if (weight >= MIN_DUNGEON_PACK_WEIGHT && weight <= MAX_DUNGEON_PACK_WEIGHT)
|
||||
{
|
||||
config.setPackWeight(weight);
|
||||
}
|
||||
@@ -267,6 +271,10 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -318,6 +326,11 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
|
||||
{
|
||||
throw new ConfigurationProcessingException("The dungeon pack config has a rule condition with an unknown dungeon type: " + typeName);
|
||||
}
|
||||
|
||||
if (condition.size() > MAX_CONDITION_LENGTH)
|
||||
{
|
||||
throw new ConfigurationProcessingException("The dungeon pack config has a rule condition that is too long: " + definition);
|
||||
}
|
||||
}
|
||||
|
||||
for (String product : WHITESPACE_SPLITTER.split(ruleProduct))
|
||||
@@ -337,7 +350,7 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
|
||||
if (productParts.length > 1)
|
||||
{
|
||||
weight = Ints.tryParse(productParts[1]);
|
||||
if (weight == null || (weight > MAX_PRODUCT_WEIGHT) || (weight < 0))
|
||||
if (weight == null || (weight > MAX_PRODUCT_WEIGHT) || (weight < MIN_PRODUCT_WEIGHT))
|
||||
{
|
||||
throw new ConfigurationProcessingException("The dungeon pack config has a rule with an invalid product weight: " + product);
|
||||
}
|
||||
@@ -352,7 +365,17 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
|
||||
{
|
||||
throw new ConfigurationProcessingException("The dungeon pack config has an unknown dungeon type in a rule: " + typeName);
|
||||
}
|
||||
|
||||
if (products.size() > MAX_PRODUCT_COUNT)
|
||||
{
|
||||
throw new ConfigurationProcessingException("The dungeon pack config has a rule with too many products: " + definition);
|
||||
}
|
||||
}
|
||||
if (products.isEmpty())
|
||||
{
|
||||
throw new ConfigurationProcessingException("The dungeon pack config has a rule with no products: " + definition);
|
||||
}
|
||||
|
||||
config.getRules().add( new DungeonChainRuleDefinition(condition, products) );
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user