Mapping coordinates to Pocket IDs and back

-Changed the Pocket placement algorithm. Instead of following a
rectangular spiral path expanding outwards from (0;0), Pockets now get
placed in a fan-shaped area expanding from (0;0) to (infinity;infinity).
-Changed maximum configurable grid size and defaulted to that
-Added a way to retrieve the Pocket ID from a Location
-Schematic loading streams are only closed if they were opened to begin
with
-Added some easier ways of testing if a Dimension is a Pocket dimension
This commit is contained in:
Mathijs Riezebos 2017-05-05 17:35:02 +02:00
parent 7574e61ede
commit 53568707f0
6 changed files with 134 additions and 41 deletions

View file

@ -23,8 +23,8 @@ public class DDConfig {
public static final boolean HAVE_CONFIG_DEFAULTS_BEEN_CHECKED_FOR_CORRECTNESS = false; //@todo check this at each non-alpha release. This field does not have a use in the mod itself, but should ensure that the developers of this mod, don't forget to reset the config defaults to the right values before releasing a non-alpha release
public static File configurationFolder;
private static int pocketGridSize = 8;
private static int maxPocketSize = 4;
private static int pocketGridSize = 32;
private static int maxPocketSize = 15;
private static int privatePocketSize = 3;
private static int publicPocketSize = 2;
private static int baseDimID = 684;
@ -68,17 +68,17 @@ public class DDConfig {
//@todo a comment in the config files about how these values only influence new worlds
Property prop;
pocketGridSize = setConfigIntWithMaxAndMin(config, Configuration.CATEGORY_GENERAL, "pocketGridSize", pocketGridSize,
"Sets how many chunks apart all pockets in pocket dimensions should be placed. [min: 4, max: 16, default: 8]", 4, 16);
"Sets how many chunks apart all pockets in pocket dimensions should be placed. [min: 4, max: 32, default: 32]", 4, 32);
DimDoors.log(DDConfig.class, "pocketGridSize was set to " + pocketGridSize);
maxPocketSize = setConfigIntWithMaxAndMin(config, Configuration.CATEGORY_GENERAL, "maxPocketSize", maxPocketSize,
"Sets how deep and wide any pocket can be. [min: 1, max: pocketGridSize/2, default: 4]", 1, (int) (((double) pocketGridSize / 2) - 0.5));
"Sets how deep and wide any pocket can be. [min: 0, max: pocketGridSize/2, default: 4]", 0, (int) (((double) pocketGridSize / 2) - 0.5));
privatePocketSize = setConfigIntWithMaxAndMin(config, Configuration.CATEGORY_GENERAL, "privatePocketSize", privatePocketSize,
"Sets how deep and wide any personal pocket can be. [min: 1, max: maxPocketsSize, default: 3]", 1, maxPocketSize);
"Sets how deep and wide any personal pocket can be. [min: 0, max: maxPocketsSize, default: 3]", 0, maxPocketSize);
publicPocketSize = setConfigIntWithMaxAndMin(config, Configuration.CATEGORY_GENERAL, "publicPocketSize", publicPocketSize,
"Sets how deep and wide any public pocket can be. [min: 1, max: maxPocketsSize, default: 2]", 1, maxPocketSize);
"Sets how deep and wide any public pocket can be. [min: 0, max: maxPocketsSize, default: 2]", 0, maxPocketSize);
prop = config.get(Configuration.CATEGORY_GENERAL, "dungeonSchematicNames", dungeonSchematicNames,
"List of names of Pockets' jSon- and Schematic file names excluding extension. Custom json and schematic files can be dropped in the corresponding folders.");
@ -109,9 +109,11 @@ public class DDConfig {
prop = config.get(Configuration.CATEGORY_GENERAL, "dangerousLimboMonolithsDisabled", DangerousLimboMonolithsDisabled,
"Is Monoliths Dangerous in Limbo disabled?");
DangerousLimboMonolithsDisabled = prop.getBoolean();
prop = config.get(Configuration.CATEGORY_GENERAL, "dangerousLimboMonolithsDisabled", MonolithTeleportationEnabled,
"Is Monolith Teleportation disabled?");
MonolithTeleportationEnabled = prop.getBoolean();
checkAndCorrectDoorRelativeDepths(config);

View file

@ -28,7 +28,7 @@ import net.minecraft.world.WorldServer;
public class Pocket {
private int ID; //this gets reset every server-load
private final int size; //in chunks
private final int size; //in chunks 0 -> 1*1 chunk, 1 -> 2*2 chunks
private final int depth;
private final EnumPocketType typeID; // dungeon, pocket, or personal pocket
private final int x; //pocket-relative 0 coordinate, should be at x * PocketRegistry.INSTANCE.gridSize * 16
@ -78,7 +78,7 @@ public class Pocket {
public void setID(int newID) {
ID = newID;
//propagate this ID to the rifts in this pocket
for (int riftID : riftIDs) {
Location riftLocation = RiftRegistry.INSTANCE.getRiftLocation(riftID);
@ -103,9 +103,9 @@ public class Pocket {
riftIDs.add(doorID);
}
Location depthZeroLocation = Location.readFromNBT(pocketNBT.getCompoundTag("depthZeroLocation"));
Pocket pocket = new Pocket(size, depth, typeID, x, z, riftIDs, depthZeroLocation);
pocket.setID(pocketNBT.getInteger("ID")); //basically re-register the pocket
NBTTagList playersTagList = (NBTTagList) pocketNBT.getTag("playerUUIDs");
for (int i = 0; i < playersTagList.tagCount(); i++) {
@ -167,15 +167,34 @@ public class Pocket {
public void validatePlayerEntry(EntityPlayer player) {
String playerUUID = player.getCachedUniqueIdString();
for (String allowedPlayerUUID : playerUUIDs) {
if (allowedPlayerUUID.equals(playerUUID)) {
return;
}
if (!playerUUIDs.contains(playerUUID)) { //the 'contains' method uses the 'equals' method to check, so for Strings, this should work.
playerUUIDs.add(playerUUID);
}
playerUUIDs.add(playerUUID);
}
public boolean isPlayerAllowedInPocket(EntityPlayer player) {
String playerUUID = player.getCachedUniqueIdString();
return playerUUIDs.contains(playerUUID);
}
public void setDepthZeroLocation(Location teleportTargetLocation) {
depthZeroLocation.loadfrom(teleportTargetLocation);
}
boolean isLocationWithinPocketBounds(final Location location, final int gridSize) {
int locX = location.getPos().getX();
int locZ = location.getPos().getY();
//minimum bounds of the pocket
int pocX = x * gridSize;
int pocZ = z * gridSize;
if (pocX <= locX && pocZ <= locZ) {
//convert to maximum bounds of the pocket
pocX = pocX + (size + 1) * 16;
pocZ = pocZ + (size + 1) * 16;
if (locX < pocX && locZ < pocZ) {
return true;
}
}
return false;
}
}

View file

@ -13,6 +13,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
@ -136,11 +137,11 @@ public class PocketRegistry {
nbt.setTag("nextUnusedIDs", nextUnusedIDTagCompound);
NBTTagCompound privatePocketsTagCompound = new NBTTagCompound();
for (String UUID: privatePockets.keySet()) {
for (String UUID : privatePockets.keySet()) {
privatePocketsTagCompound.setInteger(UUID, privatePockets.get(UUID));
}
nbt.setTag("privatePockets", privatePocketsTagCompound);
NBTTagCompound pocketsTagCompound = new NBTTagCompound();
for (EnumPocketType pocketType : pocketLists.keySet()) {
Map<Integer, Pocket> pocketList = pocketLists.get(pocketType);
@ -197,7 +198,7 @@ public class PocketRegistry {
return generatePocketAt(typeID, depth, origRiftLocation, pocketTemplate);
}
public Pocket generatePocketAt(EnumPocketType typeID, int depth, Location origRiftLocation, PocketTemplate pocketTemplate) {
//Getting the physical grid-location and the Overworld coordinates
Location shortenedLocation = getGenerationlocation(nextUnusedIDs.get(typeID), typeID);
@ -221,19 +222,32 @@ public class PocketRegistry {
public int getPrivateDimDoorID(String playerUUID) {
if (!privatePockets.containsKey(playerUUID)) {
//generate a new private pocket
int doorID = getEntranceDoorIDOfNewPocket(EnumPocketType.PRIVATE, 0, new Location(0,0,0,0)); //Location doesn't really matter in this case
int doorID = getEntranceDoorIDOfNewPocket(EnumPocketType.PRIVATE, 0, new Location(0, 0, 0, 0)); //Location doesn't really matter in this case
privatePockets.put(playerUUID, doorID);
return doorID;
}
}
return privatePockets.get(playerUUID);
}
private Location getGenerationlocation(int nextUnusedID, EnumPocketType typeID) {
int x = getSimpleX(nextUnusedID);
private Location getGenerationlocation(final int nextUnusedID, EnumPocketType typeID) {
int x;
int y = 0;
int z = getSimpleZ(nextUnusedID);
int z;
int dimID = DimDoorDimensions.getPocketDimensionType(typeID).getId();
if (nextUnusedID == 0) {
x = 0;
z = 0;
} else {
int radius = (int) Math.sqrt(nextUnusedID); //casting to int rounds down the double resulting from taking the square root
int radiusNumber = nextUnusedID - (radius * radius);
double splitter = ((double) radiusNumber) / ((double) radius); //always between 0 and 2
DimDoors.log(this.getClass(), "id is " + nextUnusedID);
DimDoors.log(this.getClass(), "Radius is " + radius);
DimDoors.log(this.getClass(), "Radius number is " + radiusNumber);
DimDoors.log(this.getClass(), "Splitter is " + splitter);
x = splitter <= 1.0 ? radius : radius - (radiusNumber - radius);
z = splitter >= 1.0 ? radius : radiusNumber;
}
Location location = new Location(dimID, x, y, z);
return location;
}
@ -250,6 +264,7 @@ public class PocketRegistry {
}
}
/*
private int getSimpleX(int ID) {
//@todo check for smaller than 0
if (ID == 0) {
@ -300,4 +315,38 @@ public class PocketRegistry {
}
return group;
}
*/
private int getPocketIDFromCoords(Location location) {
final int dimID = location.getDimensionID();
if (DimDoorDimensions.isPocketDimensionID(dimID)) {
int x = location.getPos().getX();
int z = location.getPos().getZ();
int shortX = x / (gridSize * 16);
int shortZ = z / (gridSize * 16);
if (shortX >= shortZ) {
return shortX * shortX + shortZ;
} else {
return (shortZ + 2) * shortZ - shortX;
}
}
return -1; //not in a pocket dimension
}
public boolean isPlayerAllowedToBeHere(final EntityPlayerMP player, final Location location) {
if (player.isCreative()) {
return true;
} else {
int pocketID = getPocketIDFromCoords(location);
if (pocketID < 0) { //not in a pocket dimension
return true;
} else {
EnumPocketType type = DimDoorDimensions.getPocketType(location.getDimensionID());
Pocket pocket = pocketLists.get(type).get(pocketID);
if (pocket.isPlayerAllowedInPocket(player) && pocket.isLocationWithinPocketBounds(location, gridSize)) {
return true;
}
return false;
}
}
}
}

View file

@ -44,7 +44,7 @@ public class PocketTemplate { //there is exactly one pocket placer for each diff
this.weights = weights; //chance that this Pocket will get generated
this.minDepth = minDepth; //pocket will only be generated from this Pocket-depth
this.maxDepth = maxDepth; //to this pocket depth
this.size = size; //size of content of pocket in chunks (walls are 5 thick, so size 0 will be 6*6 blocks, size 1 will be 22*22 blocks, etc.
this.size = size; //size of pocket in chunks (0 -> 1*1 chunk, 1 -> 2*2 chunks etc.)
this.schematic = schematic;
this.typeID = typeID;
}

View file

@ -49,7 +49,7 @@ public class SchematicHandler {
final private Map<String, Map<String, Integer>> dungeonNameMap = new HashMap();
//@todo, sort templates by depth over here? that'd mean that that doesn't have to be done on pocket placement each and every time
PocketTemplate getRandomDungeonPocketTemplate(int depth, int maxPocketSize) {
PocketTemplate getRandomDungeonPocketTemplate(int depth, int maxPocketSize) { //@todo maxPocketSize is passed for no reason at all here; pockets exceeding maxPocketSize have not been loaded in the first place...
List<PocketTemplate> validTemplates = new ArrayList();
int totalWeight = 0;
for (PocketTemplate template : dungeonTemplates) {
@ -168,7 +168,7 @@ public class SchematicHandler {
//DimDoors.log(SchematicHandler.class, "Checkpoint 4 reached; " + validTemplates.size() + " templates were loaded");
String subDirectory = jsonTemplate.get("directory").getAsString(); //get the subfolder in which the schematics are stored
for (PocketTemplate template : validTemplates) { //it's okay to "tap" this for-loop, even if validTemplates is empty.
String extendedTemplatelocation = subDirectory.equals("") ? template.getName() : subDirectory + "/" + template.getName(); //transform the filename accordingly
@ -180,19 +180,24 @@ public class SchematicHandler {
//determine which location to load the schematic file from (and what format)
DataInputStream schematicDataStream = null;
boolean streamOpened = false;
if (schematicStream != null) {
schematicDataStream = new DataInputStream(schematicStream);
streamOpened = true;
} else if (oldVersionSchematicStream != null) {
schematicDataStream = new DataInputStream(oldVersionSchematicStream);
streamOpened = true;
} else if (schematicFile.exists()) {
try {
schematicDataStream = new DataInputStream(new FileInputStream(schematicFile));
streamOpened = true;
} catch (FileNotFoundException ex) {
Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Schematic file " + template.getName() + ".schem did not load correctly from config folder.", ex);
}
} else if (oldVersionSchematicFile.exists()) {
try {
schematicDataStream = new DataInputStream(new FileInputStream(oldVersionSchematicFile));
streamOpened = true;
} catch (FileNotFoundException ex) {
Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Schematic file " + template.getName() + ".schematic did not load correctly from config folder.", ex);
}
@ -202,17 +207,19 @@ public class SchematicHandler {
NBTTagCompound schematicNBT;
Schematic schematic = null;
try {
schematicNBT = CompressedStreamTools.readCompressed(schematicDataStream);
schematic = Schematic.loadFromNBT(schematicNBT, template.getName());
schematicDataStream.close();
} catch (IOException ex) {
Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Schematic file for " + template.getName() + " could not be read as a valid schematic NBT file.", ex);
} finally {
if (streamOpened) {
try {
schematicNBT = CompressedStreamTools.readCompressed(schematicDataStream);
schematic = Schematic.loadFromNBT(schematicNBT, template.getName());
schematicDataStream.close();
} catch (IOException ex) {
Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Error occured while closing schematicDataStream", ex);
Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Schematic file for " + template.getName() + " could not be read as a valid schematic NBT file.", ex);
} finally {
try {
schematicDataStream.close();
} catch (IOException ex) {
Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Error occured while closing schematicDataStream", ex);
}
}
}

View file

@ -17,25 +17,32 @@ import net.minecraftforge.common.DimensionManager;
public class DimDoorDimensions {
public static DimensionType LIMBO;
private static Map<EnumPocketType, DimensionType> pocketDimensionTypes = new HashMap<>();
public static List<DimensionType> CUSTOM;
private static int minPocketDimID;
private static int maxPocketDimID;
private static final List<EnumPocketType> pocketTypes = new ArrayList<>();
private static final Map<EnumPocketType, DimensionType> pocketDimensionTypes = new HashMap<>();
private static final List<DimensionType> CUSTOM = new ArrayList<>();
public static void init() {
int dimID = DDConfig.getBaseDimID();
LIMBO = DimensionType.register("Limbo", "_limbo", dimID, WorldProviderLimbo.class, false);
dimID++;
dimID++; //@todo make this a loop over a function
minPocketDimID = dimID;
pocketTypes.add(EnumPocketType.PRIVATE);
pocketDimensionTypes.put(EnumPocketType.PRIVATE, DimensionType.register("Private", "_private", dimID, WorldProviderPersonalPocket.class, false));
dimID++;
pocketTypes.add(EnumPocketType.PUBLIC);
pocketDimensionTypes.put(EnumPocketType.PUBLIC, DimensionType.register("Public", "_public", dimID, WorldProviderPublicPocket.class, false));
dimID++;
maxPocketDimID = dimID;
pocketTypes.add(EnumPocketType.DUNGEON);
pocketDimensionTypes.put(EnumPocketType.DUNGEON, DimensionType.register("Dungeon", "_dungeon", dimID, WorldProviderDungeonPocket.class, false));
registerDimension(LIMBO);
for(EnumPocketType pocketType: pocketDimensionTypes.keySet()) {
for (EnumPocketType pocketType : pocketDimensionTypes.keySet()) {
registerDimension(pocketDimensionTypes.get(pocketType));
}
CUSTOM = new ArrayList<>();
for (int i = 0; i < 0; i++) { //@todo: For future use? Like, server owners can add their own set of DimDoors DimensionTypes via the configs? Or is this nonsense?
dimID++;
DimensionType tempType = DimensionType.register("Name", "_name", dimID, WorldProvider.class, false);
@ -47,8 +54,17 @@ public class DimDoorDimensions {
public static void registerDimension(DimensionType dimension) {
DimensionManager.registerDimension(dimension.getId(), dimension);
}
public static DimensionType getPocketDimensionType(EnumPocketType pocketType) {
return pocketDimensionTypes.get(pocketType);
}
public static boolean isPocketDimensionID(int id) {
return id >= minPocketDimID && id <= maxPocketDimID;
}
public static EnumPocketType getPocketType(int dimID) {
int index = dimID - minPocketDimID;
return pocketTypes.get(index);
}
}