Completed Implementation of Dungeon Packs #71
@@ -6,6 +6,8 @@ import java.util.Random;
|
|||||||
|
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic;
|
import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic;
|
||||||
|
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack;
|
||||||
|
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPackConfig;
|
||||||
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
|
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
|
||||||
import StevenDimDoors.mod_pocketDim.helpers.dimHelper;
|
import StevenDimDoors.mod_pocketDim.helpers.dimHelper;
|
||||||
import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException;
|
import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException;
|
||||||
@@ -16,8 +18,6 @@ public class SchematicLoader
|
|||||||
|
|
||||||
public static boolean generateDungeonPocket(LinkData link, DDProperties properties)
|
public static boolean generateDungeonPocket(LinkData link, DDProperties properties)
|
||||||
{
|
{
|
||||||
//TODO: Phase this function out in the next update. ~SenseiKiwi
|
|
||||||
|
|
||||||
if (link == null || properties == null)
|
if (link == null || properties == null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -46,7 +46,7 @@ public class SchematicLoader
|
|||||||
final long localSeed = world.getSeed() ^ 0x2F50DB9B4A8057E4L ^ computeDestinationHash(link);
|
final long localSeed = world.getSeed() ^ 0x2F50DB9B4A8057E4L ^ computeDestinationHash(link);
|
||||||
final Random random = new Random(localSeed);
|
final Random random = new Random(localSeed);
|
||||||
|
|
||||||
dungeonHelper.generateDungeonLink(link, dungeonHelper.RuinsPack, random);
|
dungeonHelper.generateDungeonLink(link, getDimDungeonPack(originDimID), random);
|
||||||
}
|
}
|
||||||
schematicPath = dimList.get(destDimID).dungeonGenerator.schematicPath;
|
schematicPath = dimList.get(destDimID).dungeonGenerator.schematicPath;
|
||||||
|
|
||||||
@@ -99,7 +99,10 @@ public class SchematicLoader
|
|||||||
dimHelper helperInstance = dimHelper.instance;
|
dimHelper helperInstance = dimHelper.instance;
|
||||||
helperInstance.moveLinkDataDestination(link, link.destXCoord, fixedY, link.destZCoord, link.destDimID, true);
|
helperInstance.moveLinkDataDestination(link, link.destXCoord, fixedY, link.destZCoord, link.destDimID, true);
|
||||||
}
|
}
|
||||||
dungeon.copyToWorld(world, new Point3D(link.destXCoord, link.destYCoord, link.destZCoord), link.linkOrientation, originDimID, destDimID);
|
DungeonPackConfig packConfig = getDimDungeonPack(destDimID).getConfig();
|
||||||
|
|
||||||
|
dungeon.copyToWorld(world, new Point3D(link.destXCoord, link.destYCoord, link.destZCoord),
|
||||||
|
link.linkOrientation, originDimID, destDimID, packConfig.doDistortDoorCoordinates());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -109,6 +112,30 @@ public class SchematicLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static DungeonPack getDimDungeonPack(int dimensionID)
|
||||||
|
{
|
||||||
|
//FIXME: This function is a workaround to our current dungeon data limitations. Modify later.
|
||||||
|
//The upcoming save format change and code overhaul will make this obsolete.
|
||||||
|
|
||||||
|
DungeonPack pack;
|
||||||
|
DungeonGenerator generator = dimHelper.dimList.get(dimensionID).dungeonGenerator;
|
||||||
|
if (generator != null)
|
||||||
|
{
|
||||||
|
pack = generator.getDungeonType().Owner;
|
||||||
|
|
||||||
|
//Make sure the pack isn't null. This can happen for dungeons with the special UNKNOWN type.
|
||||||
|
if (pack == null)
|
||||||
|
{
|
||||||
|
pack = DungeonHelper.instance().RuinsPack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pack = DungeonHelper.instance().RuinsPack;
|
||||||
|
}
|
||||||
|
return pack;
|
||||||
|
}
|
||||||
|
|
||||||
private static int adjustDestinationY(World world, int y, DungeonSchematic dungeon)
|
private static int adjustDestinationY(World world, int y, DungeonSchematic dungeon)
|
||||||
{
|
{
|
||||||
//The goal here is to guarantee that the dungeon fits within the vertical bounds
|
//The goal here is to guarantee that the dungeon fits within the vertical bounds
|
||||||
@@ -141,7 +168,7 @@ public class SchematicLoader
|
|||||||
|
|
||||||
private static DungeonSchematic checkSourceAndLoad(String schematicPath) throws FileNotFoundException, InvalidSchematicException
|
private static DungeonSchematic checkSourceAndLoad(String schematicPath) throws FileNotFoundException, InvalidSchematicException
|
||||||
{
|
{
|
||||||
//TODO: Change this code once we introduce an isInternal flag in dungeon data
|
//FIXME: Change this code once we introduce an isInternal flag in dungeon data
|
||||||
DungeonSchematic dungeon;
|
DungeonSchematic dungeon;
|
||||||
if ((new File(schematicPath)).exists())
|
if ((new File(schematicPath)).exists())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ public class CommandExportDungeon extends DDCommandBase
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
int weight = Integer.parseInt(command[3]);
|
int weight = Integer.parseInt(command[3]);
|
||||||
if (weight >= 0 && weight <= DungeonHelper.MAX_DUNGEON_WEIGHT)
|
if (weight >= DungeonHelper.MIN_DUNGEON_WEIGHT && weight <= DungeonHelper.MAX_DUNGEON_WEIGHT)
|
||||||
{
|
{
|
||||||
return exportDungeon(sender, join(command, "_", 0, 4));
|
return exportDungeon(sender, join(command, "_", 0, 4));
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,8 @@ public class CommandExportDungeon extends DDCommandBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
//If we've reached this point, then we must have an invalid weight.
|
//If we've reached this point, then we must have an invalid weight.
|
||||||
return new DDCommandResult("Invalid dungeon weight. Please specify a weight between 0 and " + DungeonHelper.MAX_DUNGEON_WEIGHT + ", inclusive.");
|
return new DDCommandResult("Invalid dungeon weight. Please specify a weight between "
|
||||||
|
+ DungeonHelper.MIN_DUNGEON_WEIGHT + " and " + DungeonHelper.MAX_DUNGEON_WEIGHT + ", inclusive.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return DDCommandResult.SUCCESS;
|
return DDCommandResult.SUCCESS;
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ public class DungeonSchematic extends Schematic {
|
|||||||
return new DungeonSchematic(Schematic.copyFromWorld(world, x, y, z, width, height, length, doCompactBounds));
|
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,
|
//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,
|
//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));
|
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.
|
//The following Random 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.
|
||||||
Random random = new Random(world.getSeed());
|
Random random = new Random(world.getSeed());
|
||||||
long factorA = random.nextLong() / 2L * 2L + 1L;
|
long factorA = random.nextLong() / 2L * 2L + 1L;
|
||||||
long factorB = 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
|
//Transform dungeon corners
|
||||||
Point3D minCorner = new Point3D(0, 0, 0);
|
Point3D minCorner = new Point3D(0, 0, 0);
|
||||||
@@ -249,7 +249,7 @@ public class DungeonSchematic extends Schematic {
|
|||||||
//Set up link data for dimensional doors
|
//Set up link data for dimensional doors
|
||||||
for (Point3D location : dimensionalDoorLocations)
|
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
|
//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 depth = dimHelper.instance.getDimDepth(originDimID) + 1;
|
||||||
int forwardNoise = MathHelper.getRandomIntegerInRange(random, -50 * depth, 150 * depth);
|
int forwardNoise;
|
||||||
int sidewaysNoise = MathHelper.getRandomIntegerInRange(random, -10 * depth, 10 * depth);
|
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
|
//Transform doorLocation to the pocket coordinate system
|
||||||
Point3D location = point.clone();
|
Point3D location = point.clone();
|
||||||
|
|||||||
@@ -15,6 +15,29 @@ public class DungeonChainRule
|
|||||||
ArrayList<String> conditionNames = source.getCondition();
|
ArrayList<String> conditionNames = source.getCondition();
|
||||||
ArrayList<WeightedContainer<String>> productNames = source.getProducts();
|
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.
|
//Obtain the IDs of dungeon types in reverse order. Reverse order makes comparing against chain histories easy.
|
||||||
condition = new int[conditionNames.size()];
|
condition = new int[conditionNames.size()];
|
||||||
for (int src = 0, dst = condition.length - 1; src < condition.length; src++, dst--)
|
for (int src = 0, dst = condition.length - 1; src < condition.length; src++, dst--)
|
||||||
|
|||||||
@@ -11,6 +11,25 @@ public class DungeonChainRuleDefinition
|
|||||||
|
|
||||||
public DungeonChainRuleDefinition(ArrayList<String> conditions, ArrayList<WeightedContainer<String>> products)
|
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.conditions = conditions;
|
||||||
this.products = products;
|
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.
|
//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!
|
//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 String name;
|
||||||
private final HashMap<String, DungeonType> nameToTypeMapping;
|
private final HashMap<String, DungeonType> nameToTypeMapping;
|
||||||
private final ArrayList<ArrayList<DungeonGenerator>> groupedDungeons;
|
private final ArrayList<ArrayList<DungeonGenerator>> groupedDungeons;
|
||||||
@@ -78,6 +80,11 @@ public class DungeonPack
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DungeonPackConfig getConfig()
|
||||||
|
{
|
||||||
|
return config.clone();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isEmpty()
|
public boolean isEmpty()
|
||||||
{
|
{
|
||||||
return allDungeons.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
|
//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.
|
//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(
|
ArrayList<DungeonGenerator> history = DungeonHelper.getDungeonChainHistory(
|
||||||
dimHelper.instance.getDimData(inbound.locDimID), this, maxSearchLength);
|
dimHelper.instance.getDimData(inbound.locDimID), this, maxSearchLength);
|
||||||
return getNextDungeon(history, random);
|
return getNextDungeon(history, random);
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ public class DungeonPackConfig
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private DungeonPackConfig(DungeonPackConfig source)
|
private DungeonPackConfig(DungeonPackConfig source)
|
||||||
{
|
{
|
||||||
this.name = source.name;
|
this.name = (source.name != null) ? source.name : null;
|
||||||
this.typeNames = (ArrayList<String>) source.typeNames.clone();
|
this.typeNames = (source.typeNames != null) ? (ArrayList<String>) source.typeNames.clone() : null;
|
||||||
this.allowDuplicatesInChain = source.allowDuplicatesInChain;
|
this.allowDuplicatesInChain = source.allowDuplicatesInChain;
|
||||||
this.allowPackChangeIn = source.allowPackChangeIn;
|
this.allowPackChangeIn = source.allowPackChangeIn;
|
||||||
this.allowPackChangeOut = source.allowPackChangeOut;
|
this.allowPackChangeOut = source.allowPackChangeOut;
|
||||||
this.distortDoorCoordinates = source.distortDoorCoordinates;
|
this.distortDoorCoordinates = source.distortDoorCoordinates;
|
||||||
this.packWeight = source.packWeight;
|
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()
|
public void validate()
|
||||||
@@ -114,7 +114,7 @@ public class DungeonPackConfig
|
|||||||
this.packWeight = packWeight;
|
this.packWeight = packWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getDistortDoorCoordinates()
|
public boolean doDistortDoorCoordinates()
|
||||||
{
|
{
|
||||||
return distortDoorCoordinates;
|
return distortDoorCoordinates;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,9 +31,13 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
|
|||||||
private final int CONFIG_VERSION = 1;
|
private final int CONFIG_VERSION = 1;
|
||||||
private final int LOOKAHEAD_LIMIT = 1024;
|
private final int LOOKAHEAD_LIMIT = 1024;
|
||||||
private final int MAX_PRODUCT_WEIGHT = 10000;
|
private final int MAX_PRODUCT_WEIGHT = 10000;
|
||||||
|
private final int MIN_PRODUCT_WEIGHT = 1;
|
||||||
private final int DEFAULT_PRODUCT_WEIGHT = 100;
|
private final int DEFAULT_PRODUCT_WEIGHT = 100;
|
||||||
private final int MAX_DUNGEON_PACK_WEIGHT = 10000;
|
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 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 String COMMENT_MARKER = "##";
|
||||||
|
|
||||||
private final Pattern DUNGEON_TYPE_PATTERN = Pattern.compile("[A-Za-z0-9_\\-]{1,20}");
|
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
|
try
|
||||||
{
|
{
|
||||||
String name = settingParts[0];
|
String name = settingParts[0].trim();
|
||||||
String value = settingParts[1];
|
String value = settingParts[1].trim();
|
||||||
if (name.equalsIgnoreCase("AllowDuplicatesInChain"))
|
if (name.equalsIgnoreCase("AllowDuplicatesInChain"))
|
||||||
{
|
{
|
||||||
config.setAllowDuplicatesInChain(parseBoolean(value));
|
config.setAllowDuplicatesInChain(parseBoolean(value));
|
||||||
@@ -258,7 +262,7 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
|
|||||||
else if (name.equalsIgnoreCase("PackWeight"))
|
else if (name.equalsIgnoreCase("PackWeight"))
|
||||||
{
|
{
|
||||||
int weight = Integer.parseInt(value);
|
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);
|
config.setPackWeight(weight);
|
||||||
}
|
}
|
||||||
@@ -267,6 +271,10 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
|
|||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
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);
|
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))
|
for (String product : WHITESPACE_SPLITTER.split(ruleProduct))
|
||||||
@@ -337,7 +350,7 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonP
|
|||||||
if (productParts.length > 1)
|
if (productParts.length > 1)
|
||||||
{
|
{
|
||||||
weight = Ints.tryParse(productParts[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);
|
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);
|
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) );
|
config.getRules().add( new DungeonChainRuleDefinition(condition, products) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ package StevenDimDoors.mod_pocketDim.helpers;
|
|||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -14,6 +16,7 @@ import java.util.Queue;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import net.minecraft.util.WeightedRandom;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import StevenDimDoors.mod_pocketDim.DDProperties;
|
import StevenDimDoors.mod_pocketDim.DDProperties;
|
||||||
import StevenDimDoors.mod_pocketDim.DimData;
|
import StevenDimDoors.mod_pocketDim.DimData;
|
||||||
@@ -27,6 +30,7 @@ import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPackConfigReader;
|
|||||||
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonType;
|
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonType;
|
||||||
import StevenDimDoors.mod_pocketDim.items.itemDimDoor;
|
import StevenDimDoors.mod_pocketDim.items.itemDimDoor;
|
||||||
import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException;
|
import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException;
|
||||||
|
import StevenDimDoors.mod_pocketDim.util.WeightedContainer;
|
||||||
|
|
||||||
public class DungeonHelper
|
public class DungeonHelper
|
||||||
{
|
{
|
||||||
@@ -42,8 +46,18 @@ public class DungeonHelper
|
|||||||
private static final String BUNDLED_DUNGEONS_LIST_PATH = "/schematics/schematics.txt";
|
private static final String BUNDLED_DUNGEONS_LIST_PATH = "/schematics/schematics.txt";
|
||||||
private static final String DUNGEON_CREATION_GUIDE_SOURCE_PATH = "/mods/DimDoors/text/How_to_add_dungeons.txt";
|
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/rules.txt";
|
||||||
|
|
||||||
public static final String SCHEMATIC_FILE_EXTENSION = ".schematic";
|
public static final String SCHEMATIC_FILE_EXTENSION = ".schematic";
|
||||||
|
|
||||||
|
|
||||||
|
private static final int MIN_PACK_SWITCH_CHANCE = 0;
|
||||||
|
private static final int PACK_SWITCH_CHANCE_PER_LEVEL = 1;
|
||||||
|
private static final int MAX_PACK_SWITCH_CHANCE = 500;
|
||||||
|
private static final int START_PACK_SWITCH_CHANCE = MAX_PACK_SWITCH_CHANCE / 9;
|
||||||
|
|
||||||
private static final int DEFAULT_DUNGEON_WEIGHT = 100;
|
private static final int DEFAULT_DUNGEON_WEIGHT = 100;
|
||||||
|
public static final int MIN_DUNGEON_WEIGHT = 1; //Prevents MC's random selection algorithm from throwing an exception
|
||||||
public static final int MAX_DUNGEON_WEIGHT = 10000; //Used to prevent overflows and math breaking down
|
public static final int MAX_DUNGEON_WEIGHT = 10000; //Used to prevent overflows and math breaking down
|
||||||
private static final int MAX_EXPORT_RADIUS = 50;
|
private static final int MAX_EXPORT_RADIUS = 50;
|
||||||
public static final short MAX_DUNGEON_WIDTH = 2 * MAX_EXPORT_RADIUS + 1;
|
public static final short MAX_DUNGEON_WIDTH = 2 * MAX_EXPORT_RADIUS + 1;
|
||||||
@@ -54,6 +68,8 @@ public class DungeonHelper
|
|||||||
private ArrayList<DungeonGenerator> registeredDungeons = new ArrayList<DungeonGenerator>();
|
private ArrayList<DungeonGenerator> registeredDungeons = new ArrayList<DungeonGenerator>();
|
||||||
|
|
||||||
public DungeonPack RuinsPack;
|
public DungeonPack RuinsPack;
|
||||||
|
private HashMap<String, DungeonPack> dungeonPackMapping = new HashMap<String, DungeonPack>();
|
||||||
|
private ArrayList<DungeonPack> dungeonPackList = new ArrayList<DungeonPack>();
|
||||||
|
|
||||||
private DungeonGenerator defaultUp;
|
private DungeonGenerator defaultUp;
|
||||||
private DungeonGenerator defaultDown;
|
private DungeonGenerator defaultDown;
|
||||||
@@ -101,32 +117,46 @@ public class DungeonHelper
|
|||||||
copyfile.copyFile(DUNGEON_CREATION_GUIDE_SOURCE_PATH, file.getAbsolutePath() + "/How_to_add_dungeons.txt");
|
copyfile.copyFile(DUNGEON_CREATION_GUIDE_SOURCE_PATH, file.getAbsolutePath() + "/How_to_add_dungeons.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
RuinsPack = new DungeonPack(createRuinsConfig());
|
//TODO: Write up a dungeon pack loading function that loads the whole pack and infers its name from the path
|
||||||
|
DungeonPackConfigReader reader = new DungeonPackConfigReader();
|
||||||
|
RuinsPack = new DungeonPack(loadDungeonPackConfig(reader, RUINS_PACK_PATH, "ruins", true));
|
||||||
|
dungeonPackMapping.put("ruins", RuinsPack);
|
||||||
|
dungeonPackList.add(RuinsPack);
|
||||||
|
|
||||||
registerBundledDungeons();
|
registerBundledDungeons();
|
||||||
registerCustomDungeons(properties.CustomSchematicDirectory);
|
registerCustomDungeons(properties.CustomSchematicDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DungeonPackConfig createRuinsConfig()
|
private static DungeonPackConfig loadDungeonPackConfig(DungeonPackConfigReader reader, String configPath, String name, boolean isInternal)
|
||||||
{
|
{
|
||||||
//This is a temporarily function for testing dungeon packs.
|
|
||||||
//It'll be removed later when we read dungeon configurations from files.
|
|
||||||
|
|
||||||
DungeonPackConfig config;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
config = (new DungeonPackConfigReader()).readFromResource("/schematics/ruins/rules.txt");
|
DungeonPackConfig config;
|
||||||
config.setName("ruins");
|
if (isInternal)
|
||||||
|
{
|
||||||
|
config = reader.readFromResource(configPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
config = reader.readFromFile(configPath);
|
||||||
|
}
|
||||||
|
config.setName(name);
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
catch (ConfigurationProcessingException e)
|
catch (ConfigurationProcessingException e)
|
||||||
{
|
{
|
||||||
//FIXME TEMPORARY DEBUG PRINT, DO SOMETHING BETTER HERE
|
System.err.println(e.getMessage());
|
||||||
System.err.println("OH GOD SOMETHING WENT WRONG WITH THE DEFAULT DUNGEON PACK CONFIG");
|
if (e.getCause() != null)
|
||||||
e.printStackTrace();
|
{
|
||||||
return null;
|
System.err.println(e.getCause());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (FileNotFoundException e)
|
||||||
|
{
|
||||||
|
System.err.println("Could not find a dungeon pack config file: " + configPath);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public List<DungeonGenerator> getRegisteredDungeons()
|
public List<DungeonGenerator> getRegisteredDungeons()
|
||||||
{
|
{
|
||||||
@@ -202,7 +232,7 @@ public class DungeonHelper
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
int weight = Integer.parseInt(dungeonData[3]);
|
int weight = Integer.parseInt(dungeonData[3]);
|
||||||
if (weight < 0 || weight > MAX_DUNGEON_WEIGHT)
|
if (weight < MIN_DUNGEON_WEIGHT || weight > MAX_DUNGEON_WEIGHT)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch (NumberFormatException e)
|
catch (NumberFormatException e)
|
||||||
@@ -336,10 +366,36 @@ public class DungeonHelper
|
|||||||
public void generateDungeonLink(LinkData inbound, DungeonPack pack, Random random)
|
public void generateDungeonLink(LinkData inbound, DungeonPack pack, Random random)
|
||||||
{
|
{
|
||||||
DungeonGenerator selection;
|
DungeonGenerator selection;
|
||||||
|
DungeonPackConfig config;
|
||||||
|
DungeonPack selectedPack;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
selection = pack.getNextDungeon(inbound, random);
|
config = pack.getConfig();
|
||||||
|
selectedPack = pack;
|
||||||
|
|
||||||
|
//Do we want to switch to another dungeon pack?
|
||||||
|
if (config.allowPackChangeOut())
|
||||||
|
{
|
||||||
|
//Calculate the chance of switching to a different pack type
|
||||||
|
int packSwitchChance;
|
||||||
|
if (dimHelper.dimList.get(inbound.locDimID).depth == 0)
|
||||||
|
{
|
||||||
|
packSwitchChance = START_PACK_SWITCH_CHANCE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
packSwitchChance = MIN_PACK_SWITCH_CHANCE + (getPackDepth(inbound, pack) - 1) * PACK_SWITCH_CHANCE_PER_LEVEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Decide randomly whether to switch packs or not
|
||||||
|
if (random.nextInt(MAX_PACK_SWITCH_CHANCE) < packSwitchChance)
|
||||||
|
{
|
||||||
|
//Find another pack
|
||||||
|
selectedPack = getRandomDungeonPack(pack, random);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selection = selectedPack.getNextDungeon(inbound, random);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -358,6 +414,29 @@ public class DungeonHelper
|
|||||||
dimHelper.instance.getDimData(inbound.destDimID).dungeonGenerator = selection;
|
dimHelper.instance.getDimData(inbound.destDimID).dungeonGenerator = selection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private DungeonPack getRandomDungeonPack(DungeonPack current, Random random)
|
||||||
|
{
|
||||||
|
DungeonPack selection = current;
|
||||||
|
ArrayList<WeightedContainer<DungeonPack>> packs = new ArrayList<WeightedContainer<DungeonPack>>(dungeonPackList.size());
|
||||||
|
|
||||||
|
//Load up a list of weighted items with any usable dungeon packs that is not the current pack
|
||||||
|
for (DungeonPack pack : dungeonPackList)
|
||||||
|
{
|
||||||
|
DungeonPackConfig config = pack.getConfig();
|
||||||
|
if (pack != current && config.allowPackChangeIn() && !pack.isEmpty())
|
||||||
|
{
|
||||||
|
packs.add(new WeightedContainer<DungeonPack>(pack, config.getPackWeight()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!packs.isEmpty())
|
||||||
|
{
|
||||||
|
//Pick a random dungeon pack
|
||||||
|
selection = ((WeightedContainer<DungeonPack>) WeightedRandom.getRandomItem(random, packs)).getData();
|
||||||
|
}
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
|
||||||
public Collection<String> getDungeonNames() {
|
public Collection<String> getDungeonNames() {
|
||||||
|
|
||||||
//Use a HashSet to guarantee that all dungeon names will be distinct.
|
//Use a HashSet to guarantee that all dungeon names will be distinct.
|
||||||
@@ -426,6 +505,38 @@ public class DungeonHelper
|
|||||||
return history;
|
return history;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int getPackDepth(LinkData inbound, DungeonPack pack)
|
||||||
|
{
|
||||||
|
//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
|
||||||
|
//Dimensions should also just keep track of pack depth internally.
|
||||||
|
|
||||||
|
int packDepth = 1;
|
||||||
|
DimData tailDim = dimHelper.dimList.get(inbound.destDimID);
|
||||||
|
boolean found;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
found = false;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
tailDim = neighbor;
|
||||||
|
found = true;
|
||||||
|
packDepth++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (found);
|
||||||
|
|
||||||
|
return packDepth;
|
||||||
|
}
|
||||||
|
|
||||||
public static ArrayList<DungeonGenerator> getFlatDungeonTree(DimData dimData, int maxSize)
|
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
|
//TODO: I've improved this code for the time being. However, searching across links is a flawed approach. A player could
|
||||||
|
|||||||
Reference in New Issue
Block a user