Completed Implementation of Dungeon Packs #71
@@ -4,13 +4,11 @@ import java.io.File;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
|
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack;
|
||||||
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonType;
|
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonType;
|
||||||
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
|
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
|
||||||
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
|
|
||||||
public class DungeonGenerator implements Serializable
|
public class DungeonGenerator implements Serializable
|
||||||
{
|
{
|
||||||
//This static field is hax so that I don't have to add an instance field to DungeonGenerator to support DungeonType.
|
//This static field is hax so that I don't have to add an instance field to DungeonGenerator to support DungeonType.
|
||||||
@@ -48,7 +46,13 @@ public class DungeonGenerator implements Serializable
|
|||||||
{
|
{
|
||||||
File file = new File(schematicPath);
|
File file = new File(schematicPath);
|
||||||
String typeName = file.getName().split("_")[0];
|
String typeName = file.getName().split("_")[0];
|
||||||
type = DungeonHelper.instance().RuinsPack.getType(typeName);
|
String packName = file.getParentFile().getName();
|
||||||
|
DungeonPack pack = DungeonHelper.instance().getDungeonPack(packName);
|
||||||
|
if (pack == null)
|
||||||
|
{
|
||||||
|
pack = DungeonHelper.instance().getDungeonPack("ruins");
|
||||||
|
}
|
||||||
|
type = pack.getType(typeName);
|
||||||
}
|
}
|
||||||
catch (Exception e) { }
|
catch (Exception e) { }
|
||||||
if (type == null)
|
if (type == null)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ 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.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 +17,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,10 +45,9 @@ 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, dungeonHelper.getDimDungeonPack(originDimID), random);
|
||||||
}
|
}
|
||||||
schematicPath = dimList.get(destDimID).dungeonGenerator.schematicPath;
|
schematicPath = dimList.get(destDimID).dungeonGenerator.schematicPath;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -99,7 +97,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 = dungeonHelper.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)
|
||||||
@@ -141,7 +142,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())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public class CommandExportDungeon extends DDCommandBase
|
|||||||
//TODO: This validation should be in DungeonHelper or in another class. We should move it
|
//TODO: This validation should be in DungeonHelper or in another class. We should move it
|
||||||
//during the save file format rewrite. ~SenseiKiwi
|
//during the save file format rewrite. ~SenseiKiwi
|
||||||
|
|
||||||
if (!dungeonHelper.validateDungeonType(command[0]))
|
if (!dungeonHelper.validateDungeonType(command[0], dungeonHelper.getDungeonPack("ruins")))
|
||||||
{
|
{
|
||||||
return new DDCommandResult("Error: Invalid dungeon type. Please use one of the existing types.");
|
return new DDCommandResult("Error: Invalid dungeon type. Please use one of the existing types.");
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
@@ -132,7 +133,7 @@ public class CommandExportDungeon extends DDCommandBase
|
|||||||
if (dungeonHelper.exportDungeon(player.worldObj, x, y, z, exportPath))
|
if (dungeonHelper.exportDungeon(player.worldObj, x, y, z, exportPath))
|
||||||
{
|
{
|
||||||
player.sendChatToPlayer("Saved dungeon schematic in " + exportPath);
|
player.sendChatToPlayer("Saved dungeon schematic in " + exportPath);
|
||||||
dungeonHelper.registerDungeon(exportPath, false, true);
|
dungeonHelper.registerDungeon(exportPath, dungeonHelper.getDungeonPack("ruins"), false, true);
|
||||||
return DDCommandResult.SUCCESS;
|
return DDCommandResult.SUCCESS;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -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,14 @@ package StevenDimDoors.mod_pocketDim.helpers;
|
|||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
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 +17,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,24 +31,56 @@ 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
|
||||||
{
|
{
|
||||||
|
//TODO: File-handling functionality should be spun off to a helper class later
|
||||||
|
private static class DirectoryFilter implements FileFilter
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean accept(File file)
|
||||||
|
{
|
||||||
|
return file.isDirectory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SchematicFileFilter implements FileFilter
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean accept(File file)
|
||||||
|
{
|
||||||
|
return file.isFile() && file.getName().endsWith(SCHEMATIC_FILE_EXTENSION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static DungeonHelper instance = null;
|
private static DungeonHelper instance = null;
|
||||||
private static DDProperties properties = null;
|
private static DDProperties properties = null;
|
||||||
|
|
||||||
public static final Pattern SCHEMATIC_NAME_PATTERN = Pattern.compile("[A-Za-z0-9_\\-]+");
|
public static final Pattern SCHEMATIC_NAME_PATTERN = Pattern.compile("[A-Za-z0-9_\\-]+");
|
||||||
public static final Pattern DUNGEON_NAME_PATTERN = Pattern.compile("[A-Za-z0-9\\-]+");
|
public static final Pattern DUNGEON_NAME_PATTERN = Pattern.compile("[A-Za-z0-9\\-]+");
|
||||||
|
|
||||||
|
public static final String SCHEMATIC_FILE_EXTENSION = ".schematic";
|
||||||
|
|
||||||
private static final String DEFAULT_UP_SCHEMATIC_PATH = "/schematics/core/simpleStairsUp.schematic";
|
private static final String DEFAULT_UP_SCHEMATIC_PATH = "/schematics/core/simpleStairsUp.schematic";
|
||||||
private static final String DEFAULT_DOWN_SCHEMATIC_PATH = "/schematics/core/simpleStairsDown.schematic";
|
private static final String DEFAULT_DOWN_SCHEMATIC_PATH = "/schematics/core/simpleStairsDown.schematic";
|
||||||
private static final String DEFAULT_ERROR_SCHEMATIC_PATH = "/schematics/core/somethingBroke.schematic";
|
private static final String DEFAULT_ERROR_SCHEMATIC_PATH = "/schematics/core/somethingBroke.schematic";
|
||||||
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";
|
||||||
|
private static final String BUNDLED_RUINS_LIST_PATH = "/schematics/ruins.txt";
|
||||||
|
private static final String STANDARD_CONFIG_FILE_NAME = "rules.txt";
|
||||||
|
|
||||||
|
private static final int NETHER_DIMENSION_ID = -1;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
public static final String SCHEMATIC_FILE_EXTENSION = ".schematic";
|
|
||||||
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;
|
||||||
public static final short MAX_DUNGEON_HEIGHT = MAX_DUNGEON_WIDTH;
|
public static final short MAX_DUNGEON_HEIGHT = MAX_DUNGEON_WIDTH;
|
||||||
@@ -53,7 +89,9 @@ public class DungeonHelper
|
|||||||
private ArrayList<DungeonGenerator> untaggedDungeons = new ArrayList<DungeonGenerator>();
|
private ArrayList<DungeonGenerator> untaggedDungeons = new ArrayList<DungeonGenerator>();
|
||||||
private ArrayList<DungeonGenerator> registeredDungeons = new ArrayList<DungeonGenerator>();
|
private ArrayList<DungeonGenerator> registeredDungeons = new ArrayList<DungeonGenerator>();
|
||||||
|
|
||||||
public DungeonPack RuinsPack;
|
private 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,30 +139,82 @@ 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());
|
DungeonPackConfigReader reader = new DungeonPackConfigReader();
|
||||||
|
registerBundledDungeons(reader);
|
||||||
registerBundledDungeons();
|
registerCustomDungeons(properties.CustomSchematicDirectory, reader);
|
||||||
registerCustomDungeons(properties.CustomSchematicDirectory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DungeonPackConfig createRuinsConfig()
|
private static DungeonPackConfig loadDungeonPackConfig(String configPath, String name, boolean isInternal, DungeonPackConfigReader reader)
|
||||||
{
|
{
|
||||||
//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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void 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);
|
||||||
|
String name = packDirectory.getName().toUpperCase();
|
||||||
|
//TODO: ADD VALIDATION HERE?
|
||||||
|
|
||||||
|
//Check for naming conflicts
|
||||||
|
//That could happen if a user has a custom pack with a name that conflicts with a bundled pack,
|
||||||
|
//or if a user is running Linux and has two directories with names differing only by capitalization.
|
||||||
|
|
||||||
|
DungeonPack pack = dungeonPackMapping.get(name);
|
||||||
|
if (pack == null)
|
||||||
|
{
|
||||||
|
//Load the pack's configuration file
|
||||||
|
String configPath = directory + File.separator + STANDARD_CONFIG_FILE_NAME;
|
||||||
|
DungeonPackConfig config = loadDungeonPackConfig(configPath, name, isInternal, reader);
|
||||||
|
if (config == null)
|
||||||
|
{
|
||||||
|
System.err.println("Could not load config file: " + configPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Register the pack
|
||||||
|
pack = new DungeonPack(config);
|
||||||
|
dungeonPackMapping.put(name, pack);
|
||||||
|
dungeonPackList.add(pack);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Show a warning that there is a naming conflict but keep going. People can use this to extend
|
||||||
|
//our built-in packs with custom schematics without tampering with our mod's JAR file.
|
||||||
|
System.err.println("A dungeon pack has the same name as another pack that has already been loaded: " + directory);
|
||||||
|
System.err.println("We will try to load its schematics but will not check its config file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Register the dungeons! ^_^
|
||||||
|
for (String schematicPath : schematics)
|
||||||
|
{
|
||||||
|
registerDungeon(schematicPath, pack, isInternal, verbose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,6 +243,44 @@ public class DungeonHelper
|
|||||||
return defaultDown;
|
return defaultDown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DungeonPack getDungeonPack(String name)
|
||||||
|
{
|
||||||
|
//TODO: This function might be obsolete after the new save format is implemented.
|
||||||
|
return dungeonPackMapping.get(name.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
public 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 = RuinsPack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dimensionID == NETHER_DIMENSION_ID)
|
||||||
|
{
|
||||||
|
//TODO: Change this to the nether-side pack later ^_^
|
||||||
|
pack = RuinsPack;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pack = RuinsPack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pack;
|
||||||
|
}
|
||||||
|
|
||||||
public LinkData createCustomDungeonDoor(World world, int x, int y, int z)
|
public LinkData createCustomDungeonDoor(World world, int x, int y, int z)
|
||||||
{
|
{
|
||||||
//Create a link above the specified position. Link to a new pocket dimension.
|
//Create a link above the specified position. Link to a new pocket dimension.
|
||||||
@@ -165,13 +293,13 @@ public class DungeonHelper
|
|||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean validateDungeonType(String type)
|
public boolean validateDungeonType(String type, DungeonPack pack)
|
||||||
{
|
{
|
||||||
//Check if the dungeon type is valid
|
//Check if the dungeon type is valid
|
||||||
return RuinsPack.isKnownType(type);
|
return pack.isKnownType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean validateSchematicName(String name)
|
public boolean validateSchematicName(String name, DungeonPack pack)
|
||||||
{
|
{
|
||||||
String[] dungeonData;
|
String[] dungeonData;
|
||||||
|
|
||||||
@@ -185,7 +313,7 @@ public class DungeonHelper
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
//Check if the dungeon type is valid
|
//Check if the dungeon type is valid
|
||||||
if (!validateDungeonType(dungeonData[0]))
|
if (!validateDungeonType(dungeonData[0], pack))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//Check if the name is valid
|
//Check if the name is valid
|
||||||
@@ -202,7 +330,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)
|
||||||
@@ -214,7 +342,7 @@ public class DungeonHelper
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerDungeon(String schematicPath, boolean isInternal, boolean verbose)
|
public void registerDungeon(String schematicPath, DungeonPack pack, boolean isInternal, boolean verbose)
|
||||||
{
|
{
|
||||||
//We use schematicPath as the real path for internal files (inside our JAR) because it seems
|
//We use schematicPath as the real path for internal files (inside our JAR) because it seems
|
||||||
//that File tries to interpret it as a local drive path and mangles it.
|
//that File tries to interpret it as a local drive path and mangles it.
|
||||||
@@ -223,19 +351,19 @@ public class DungeonHelper
|
|||||||
String path = isInternal ? schematicPath : schematicFile.getAbsolutePath();
|
String path = isInternal ? schematicPath : schematicFile.getAbsolutePath();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (validateSchematicName(name))
|
if (validateSchematicName(name, pack))
|
||||||
{
|
{
|
||||||
//Strip off the file extension while splitting the file name
|
//Strip off the file extension while splitting the file name
|
||||||
String[] dungeonData = name.substring(0, name.length() - SCHEMATIC_FILE_EXTENSION.length()).split("_");
|
String[] dungeonData = name.substring(0, name.length() - SCHEMATIC_FILE_EXTENSION.length()).split("_");
|
||||||
|
|
||||||
DungeonType dungeonType = RuinsPack.getType(dungeonData[0]);
|
DungeonType dungeonType = pack.getType(dungeonData[0]);
|
||||||
boolean isOpen = dungeonData[2].equalsIgnoreCase("open");
|
boolean isOpen = dungeonData[2].equalsIgnoreCase("open");
|
||||||
int weight = (dungeonData.length == 4) ? Integer.parseInt(dungeonData[3]) : DEFAULT_DUNGEON_WEIGHT;
|
int weight = (dungeonData.length == 4) ? Integer.parseInt(dungeonData[3]) : DEFAULT_DUNGEON_WEIGHT;
|
||||||
|
|
||||||
//Add this custom dungeon to the list corresponding to its type
|
//Add this custom dungeon to the list corresponding to its type
|
||||||
DungeonGenerator generator = new DungeonGenerator(weight, path, isOpen, dungeonType);
|
DungeonGenerator generator = new DungeonGenerator(weight, path, isOpen, dungeonType);
|
||||||
|
|
||||||
RuinsPack.addDungeon(generator);
|
pack.addDungeon(generator);
|
||||||
registeredDungeons.add(generator);
|
registeredDungeons.add(generator);
|
||||||
if (verbose)
|
if (verbose)
|
||||||
{
|
{
|
||||||
@@ -246,37 +374,82 @@ public class DungeonHelper
|
|||||||
{
|
{
|
||||||
if (verbose)
|
if (verbose)
|
||||||
{
|
{
|
||||||
System.out.println("Could not parse dungeon filename, not adding dungeon to generation lists");
|
System.out.println("The following dungeon name is invalid for its given pack. It will not be generated naturally: " + schematicPath);
|
||||||
}
|
}
|
||||||
untaggedDungeons.add(new DungeonGenerator(DEFAULT_DUNGEON_WEIGHT, path, true, DungeonType.UNKNOWN_TYPE));
|
untaggedDungeons.add(new DungeonGenerator(DEFAULT_DUNGEON_WEIGHT, path, true, DungeonType.UNKNOWN_TYPE));
|
||||||
System.out.println("Registered untagged dungeon: " + name);
|
System.out.println("Registered untagged dungeon: " + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
System.err.println("Failed to register dungeon: " + name);
|
System.err.println("Failed to register dungeon: " + name);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerCustomDungeons(String path)
|
private void registerCustomDungeons(String path, DungeonPackConfigReader reader)
|
||||||
{
|
{
|
||||||
|
File[] schematics;
|
||||||
|
File[] packDirectories;
|
||||||
|
File[] packFiles;
|
||||||
|
ArrayList<String> packFilePaths;
|
||||||
File directory = new File(path);
|
File directory = new File(path);
|
||||||
File[] schematicNames = directory.listFiles();
|
SchematicFileFilter schematicFileFilter = new SchematicFileFilter();
|
||||||
|
|
||||||
if (schematicNames != null)
|
//Check that the Ruins pack has been loaded
|
||||||
|
if (RuinsPack == null)
|
||||||
{
|
{
|
||||||
for (File schematicFile: schematicNames)
|
throw new IllegalStateException("Cannot register custom dungeons without first loading the Ruins dungeon pack.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Load stray dungeons directly in the custom dungeons folder
|
||||||
|
schematics = directory.listFiles(schematicFileFilter);
|
||||||
|
if (schematics != null)
|
||||||
|
{
|
||||||
|
for (File schematicFile : schematics)
|
||||||
{
|
{
|
||||||
if (schematicFile.getName().endsWith(SCHEMATIC_FILE_EXTENSION))
|
registerDungeon(schematicFile.getPath(), RuinsPack, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.err.println("Could not retrieve the list of schematics stored in the custom dungeons directory!");
|
||||||
|
}
|
||||||
|
schematics = null; //Release memory
|
||||||
|
|
||||||
|
//Load the custom dungeon packs
|
||||||
|
packDirectories = directory.listFiles(new DirectoryFilter());
|
||||||
|
if (packDirectories != null)
|
||||||
|
{
|
||||||
|
//Loop through each directory, which is assumed to be a dungeon pack
|
||||||
|
for (File packDirectory : packDirectories)
|
||||||
|
{
|
||||||
|
//List the schematics within the dungeon pack directory
|
||||||
|
packFiles = packDirectory.listFiles(schematicFileFilter);
|
||||||
|
if (packFiles != null)
|
||||||
{
|
{
|
||||||
registerDungeon(schematicFile.getPath(), false, true);
|
//Copy the pack files' paths into an ArrayList for use with registerDungeonPack()
|
||||||
|
packFilePaths = new ArrayList<String>(packFiles.length);
|
||||||
|
for (File packFile : packFiles)
|
||||||
|
{
|
||||||
|
packFilePaths.add(packFile.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
registerDungeonPack(packDirectory.getAbsolutePath(), packFilePaths, false, true, reader);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.err.println("Could not retrieve the list of schematics in a dungeon pack: " + packDirectory.getPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.err.println("Could not retrieve the list of dungeon pack directories in the custom dungeons directory!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerBundledDungeons()
|
private void registerBundledDungeons(DungeonPackConfigReader reader)
|
||||||
{
|
{
|
||||||
//Register the core schematics
|
//Register the core schematics
|
||||||
//These are used for debugging and in case of unusual errors while loading dungeons
|
//These are used for debugging and in case of unusual errors while loading dungeons
|
||||||
@@ -285,31 +458,46 @@ public class DungeonHelper
|
|||||||
defaultError = new DungeonGenerator(DEFAULT_DUNGEON_WEIGHT, DEFAULT_ERROR_SCHEMATIC_PATH, true, DungeonType.UNKNOWN_TYPE);
|
defaultError = new DungeonGenerator(DEFAULT_DUNGEON_WEIGHT, DEFAULT_ERROR_SCHEMATIC_PATH, true, DungeonType.UNKNOWN_TYPE);
|
||||||
|
|
||||||
//Open the list of dungeons packaged with our mod and register their schematics
|
//Open the list of dungeons packaged with our mod and register their schematics
|
||||||
InputStream listStream = this.getClass().getResourceAsStream(BUNDLED_DUNGEONS_LIST_PATH);
|
registerBundledPack(BUNDLED_RUINS_LIST_PATH, RUINS_PACK_PATH, "Ruins", reader);
|
||||||
|
RuinsPack = getDungeonPack("Ruins");
|
||||||
|
|
||||||
|
System.out.println("Finished registering bundled dungeon packs");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerBundledPack(String listPath, String packPath, String name, DungeonPackConfigReader reader)
|
||||||
|
{
|
||||||
|
System.out.println("Registering bundled dungeon pack: " + name);
|
||||||
|
|
||||||
|
InputStream listStream = this.getClass().getResourceAsStream(listPath);
|
||||||
if (listStream == null)
|
if (listStream == null)
|
||||||
{
|
{
|
||||||
System.err.println("Unable to open list of bundled dungeon schematics.");
|
System.err.println("Unable to open list of bundled dungeon schematics for " + name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
//Read the list of schematics that come with a bundled pack
|
||||||
BufferedReader listReader = new BufferedReader(new InputStreamReader(listStream));
|
BufferedReader listReader = new BufferedReader(new InputStreamReader(listStream));
|
||||||
|
ArrayList<String> schematics = new ArrayList<String>();
|
||||||
String schematicPath = listReader.readLine();
|
String schematicPath = listReader.readLine();
|
||||||
while (schematicPath != null)
|
while (schematicPath != null)
|
||||||
{
|
{
|
||||||
schematicPath = schematicPath.trim();
|
schematicPath = schematicPath.trim();
|
||||||
if (!schematicPath.isEmpty())
|
if (!schematicPath.isEmpty())
|
||||||
{
|
{
|
||||||
registerDungeon(schematicPath, true, false);
|
schematics.add(schematicPath);
|
||||||
}
|
}
|
||||||
schematicPath = listReader.readLine();
|
schematicPath = listReader.readLine();
|
||||||
}
|
}
|
||||||
listReader.close();
|
listReader.close();
|
||||||
|
|
||||||
|
//Register the pack
|
||||||
|
registerDungeonPack(packPath, schematics, true, false, reader);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
System.err.println("An exception occurred while reading the list of bundled dungeon schematics.");
|
System.err.println("An exception occurred while reading the list of bundled dungeon schematics for " + name);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,10 +524,38 @@ 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;
|
||||||
|
|
||||||
|
//Are we allowed 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Pick the next dungeon
|
||||||
|
selection = selectedPack.getNextDungeon(inbound, random);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -358,6 +574,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 +665,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