2013-02-17 21:46:16 -05:00
|
|
|
package StevenDimDoors.mod_pocketDim;
|
2013-06-01 21:43:56 -04:00
|
|
|
import java.io.File;
|
2013-07-30 13:58:14 -04:00
|
|
|
import java.io.FileNotFoundException;
|
2013-07-31 08:05:58 -04:00
|
|
|
import java.util.HashMap;
|
2013-08-04 19:27:34 -04:00
|
|
|
import java.util.Random;
|
2013-02-17 21:46:16 -05:00
|
|
|
|
|
|
|
import net.minecraft.world.World;
|
2013-07-30 13:58:14 -04:00
|
|
|
import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic;
|
2013-08-21 14:26:10 -04:00
|
|
|
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPackConfig;
|
2013-06-13 15:44:11 -04:00
|
|
|
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
|
2013-06-10 17:03:52 -04:00
|
|
|
import StevenDimDoors.mod_pocketDim.helpers.dimHelper;
|
2013-07-30 13:58:14 -04:00
|
|
|
import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException;
|
2013-06-13 19:01:54 -04:00
|
|
|
|
2013-02-17 21:46:16 -05:00
|
|
|
public class SchematicLoader
|
2013-07-31 08:05:58 -04:00
|
|
|
{
|
2013-07-30 13:58:14 -04:00
|
|
|
private SchematicLoader() { }
|
2013-06-26 23:54:06 -04:00
|
|
|
|
2013-07-31 08:05:58 -04:00
|
|
|
public static boolean generateDungeonPocket(LinkData link, DDProperties properties)
|
2013-06-13 19:01:54 -04:00
|
|
|
{
|
2013-07-31 08:05:58 -04:00
|
|
|
if (link == null || properties == null)
|
2013-06-25 22:10:15 -04:00
|
|
|
{
|
2013-07-31 08:05:58 -04:00
|
|
|
return false;
|
2013-02-17 21:46:16 -05:00
|
|
|
}
|
2013-07-30 13:58:14 -04:00
|
|
|
try
|
2013-06-13 19:01:54 -04:00
|
|
|
{
|
2013-07-31 08:05:58 -04:00
|
|
|
String schematicPath;
|
2013-07-30 13:58:14 -04:00
|
|
|
int originDimID = link.locDimID;
|
|
|
|
int destDimID = link.destDimID;
|
2013-07-31 08:05:58 -04:00
|
|
|
HashMap<Integer, DimData> dimList = dimHelper.dimList;
|
2013-08-05 09:48:49 -04:00
|
|
|
DungeonHelper dungeonHelper = DungeonHelper.instance();
|
2013-08-04 19:27:34 -04:00
|
|
|
World world;
|
2013-07-31 08:05:58 -04:00
|
|
|
|
|
|
|
if (dimList.containsKey(destDimID))
|
2013-02-17 21:46:16 -05:00
|
|
|
{
|
2013-08-04 19:27:34 -04:00
|
|
|
dimList.get(destDimID).hasBeenFilled = true;
|
|
|
|
if (dimHelper.getWorld(destDimID) == null)
|
|
|
|
{
|
|
|
|
dimHelper.initDimension(destDimID);
|
|
|
|
}
|
|
|
|
world = dimHelper.getWorld(destDimID);
|
|
|
|
|
2013-07-31 08:05:58 -04:00
|
|
|
if (dimList.get(destDimID).dungeonGenerator == null)
|
|
|
|
{
|
2013-08-05 20:16:45 -04:00
|
|
|
//TODO: We should centralize RNG initialization and world-seed modifiers for each specific application.
|
2013-08-15 07:29:37 -04:00
|
|
|
final long localSeed = world.getSeed() ^ 0x2F50DB9B4A8057E4L ^ computeDestinationHash(link);
|
|
|
|
final Random random = new Random(localSeed);
|
2013-08-04 19:27:34 -04:00
|
|
|
|
2013-08-21 14:49:41 -04:00
|
|
|
dungeonHelper.generateDungeonLink(link, dungeonHelper.getDimDungeonPack(originDimID), random);
|
2013-07-31 08:05:58 -04:00
|
|
|
}
|
2013-08-22 02:25:26 -04:00
|
|
|
schematicPath = dimList.get(destDimID).dungeonGenerator.schematicPath;
|
2013-02-17 21:46:16 -05:00
|
|
|
}
|
2013-07-30 13:58:14 -04:00
|
|
|
else
|
2013-02-17 21:46:16 -05:00
|
|
|
{
|
2013-07-31 08:05:58 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
DungeonSchematic dungeon = checkSourceAndLoad(schematicPath);
|
2013-07-31 12:09:47 -04:00
|
|
|
boolean valid;
|
2013-07-31 08:05:58 -04:00
|
|
|
|
|
|
|
//Validate the dungeon's dimensions
|
2013-07-31 12:09:47 -04:00
|
|
|
if (hasValidDimensions(dungeon))
|
|
|
|
{
|
|
|
|
dungeon.applyImportFilters(properties);
|
|
|
|
|
|
|
|
//Check that the dungeon has an entrance or we'll have a crash
|
|
|
|
if (dungeon.getEntranceDoorLocation() != null)
|
|
|
|
{
|
|
|
|
valid = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
System.err.println("The following schematic file does not have an entrance: " + schematicPath);
|
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
System.err.println("The following schematic file has dimensions that exceed the maximum permitted dimensions for dungeons: " + schematicPath);
|
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!valid)
|
2013-07-31 08:05:58 -04:00
|
|
|
{
|
|
|
|
//TODO: In the future, remove this dungeon from the generation lists altogether.
|
|
|
|
//That will have to wait until our code is updated to support that more easily.
|
|
|
|
System.err.println("The dungeon will not be loaded.");
|
2013-08-05 09:48:49 -04:00
|
|
|
DungeonGenerator defaultError = dungeonHelper.getDefaultErrorDungeon();
|
2013-08-01 13:00:27 -04:00
|
|
|
dimList.get(destDimID).dungeonGenerator = defaultError;
|
|
|
|
dungeon = checkSourceAndLoad(defaultError.schematicPath);
|
2013-07-31 12:09:47 -04:00
|
|
|
dungeon.applyImportFilters(properties);
|
2013-06-30 00:24:44 -04:00
|
|
|
}
|
2013-06-26 23:54:06 -04:00
|
|
|
|
2013-07-31 12:09:47 -04:00
|
|
|
//Adjust the height at which the dungeon is placed to prevent vertical clipping
|
2013-08-01 13:37:33 -04:00
|
|
|
int fixedY = adjustDestinationY(world, link.destYCoord, dungeon);
|
|
|
|
if (fixedY != link.destYCoord)
|
|
|
|
{
|
|
|
|
dimHelper helperInstance = dimHelper.instance;
|
2013-08-01 18:01:42 -04:00
|
|
|
helperInstance.moveLinkDataDestination(link, link.destXCoord, fixedY, link.destZCoord, link.destDimID, true);
|
2013-08-21 14:26:10 -04:00
|
|
|
}
|
2013-08-21 14:49:41 -04:00
|
|
|
DungeonPackConfig packConfig = dungeonHelper.getDimDungeonPack(destDimID).getConfig();
|
2013-08-21 14:26:10 -04:00
|
|
|
|
|
|
|
dungeon.copyToWorld(world, new Point3D(link.destXCoord, link.destYCoord, link.destZCoord),
|
|
|
|
link.linkOrientation, originDimID, destDimID, packConfig.doDistortDoorCoordinates());
|
2013-07-31 08:05:58 -04:00
|
|
|
return true;
|
2013-07-15 16:58:44 -04:00
|
|
|
}
|
2013-07-31 08:05:58 -04:00
|
|
|
catch (Exception e)
|
2013-06-26 23:54:06 -04:00
|
|
|
{
|
2013-07-30 13:58:14 -04:00
|
|
|
e.printStackTrace();
|
2013-07-31 08:05:58 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2013-08-21 14:26:10 -04:00
|
|
|
|
2013-07-31 12:09:47 -04:00
|
|
|
private static int adjustDestinationY(World world, int y, DungeonSchematic dungeon)
|
|
|
|
{
|
|
|
|
//The goal here is to guarantee that the dungeon fits within the vertical bounds
|
|
|
|
//of the world while shifting it as little as possible.
|
|
|
|
int destY = y;
|
|
|
|
|
|
|
|
//Is the top of the dungeon going to be at Y < worldHeight?
|
|
|
|
int entranceY = dungeon.getEntranceDoorLocation().getY();
|
|
|
|
int pocketTop = (dungeon.getHeight() - 1) + destY - entranceY;
|
|
|
|
int worldHeight = world.getHeight();
|
|
|
|
if (pocketTop >= worldHeight)
|
|
|
|
{
|
|
|
|
destY = (worldHeight - 1) - (dungeon.getHeight() - 1) + entranceY;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Is the bottom of the dungeon at Y >= 0?
|
|
|
|
if (destY < entranceY)
|
|
|
|
{
|
|
|
|
destY = entranceY;
|
|
|
|
}
|
|
|
|
return destY;
|
|
|
|
}
|
|
|
|
|
2013-07-31 08:05:58 -04:00
|
|
|
private static boolean hasValidDimensions(DungeonSchematic dungeon)
|
|
|
|
{
|
|
|
|
return (dungeon.getWidth() <= DungeonHelper.MAX_DUNGEON_WIDTH &&
|
|
|
|
dungeon.getHeight() <= DungeonHelper.MAX_DUNGEON_HEIGHT &&
|
|
|
|
dungeon.getLength() <= DungeonHelper.MAX_DUNGEON_LENGTH);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static DungeonSchematic checkSourceAndLoad(String schematicPath) throws FileNotFoundException, InvalidSchematicException
|
|
|
|
{
|
2013-08-21 14:26:10 -04:00
|
|
|
//FIXME: Change this code once we introduce an isInternal flag in dungeon data
|
2013-07-31 08:05:58 -04:00
|
|
|
DungeonSchematic dungeon;
|
|
|
|
if ((new File(schematicPath)).exists())
|
|
|
|
{
|
|
|
|
dungeon = DungeonSchematic.readFromFile(schematicPath);
|
2013-06-26 23:54:06 -04:00
|
|
|
}
|
2013-07-31 08:05:58 -04:00
|
|
|
else
|
2013-06-26 23:54:06 -04:00
|
|
|
{
|
2013-07-31 08:05:58 -04:00
|
|
|
dungeon = DungeonSchematic.readFromResource(schematicPath);
|
2013-06-26 23:54:06 -04:00
|
|
|
}
|
2013-07-31 08:05:58 -04:00
|
|
|
return dungeon;
|
2013-06-13 19:01:54 -04:00
|
|
|
}
|
2013-08-15 07:29:37 -04:00
|
|
|
|
|
|
|
private static long computeDestinationHash(LinkData link)
|
|
|
|
{
|
|
|
|
//Time for some witchcraft.
|
|
|
|
//The code here is inspired by a discussion on Stack Overflow regarding hash codes for 3D.
|
|
|
|
//Source: http://stackoverflow.com/questions/9858376/hashcode-for-3d-integer-coordinates-with-high-spatial-coherence
|
|
|
|
|
|
|
|
//Use 8 bits from Y and 24 bits from X and Z. Mix in 8 bits from the destination dim ID too - that means
|
|
|
|
//even if you aligned two doors perfectly between two pockets, it's unlikely they would lead to the same dungeon.
|
|
|
|
|
|
|
|
int bit;
|
|
|
|
int index;
|
|
|
|
long hash;
|
|
|
|
int w = link.destDimID;
|
|
|
|
int x = link.destXCoord;
|
|
|
|
int y = link.destYCoord;
|
|
|
|
int z = link.destZCoord;
|
|
|
|
|
|
|
|
hash = 0;
|
|
|
|
index = 0;
|
|
|
|
for (bit = 0; bit < 8; bit++)
|
|
|
|
{
|
|
|
|
hash |= ((w >> bit) & 1) << index;
|
|
|
|
index++;
|
|
|
|
hash |= ((x >> bit) & 1) << index;
|
|
|
|
index++;
|
|
|
|
hash |= ((y >> bit) & 1) << index;
|
|
|
|
index++;
|
|
|
|
hash |= ((z >> bit) & 1) << index;
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
for (; bit < 24; bit++)
|
|
|
|
{
|
|
|
|
hash |= ((x >> bit) & 1) << index;
|
|
|
|
index++;
|
|
|
|
hash |= ((z >> bit) & 1) << index;
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
return hash;
|
|
|
|
}
|
2013-02-17 21:46:16 -05:00
|
|
|
}
|